SEP4020 Linux2

Size: px
Start display at page:

Download "SEP4020 Linux2"

Transcription

1 SEP4020 Linux SDK Develop Manual Version 3.4 南京博芯电子技术有限公司

2 版权声明 本手册版权归属南京博芯电子技术有限公司所有, 并保留一切权力 没有南京博芯电子技术有限公司的许可 ( 书面形式 ), 任何单位及个人不得擅自摘录本手册部分或全部, 违者我们将追究其法律责任 TEL: FAX: 技术社区 : -2-

3 目 录 Version 第一章 SEP4020 Linux SDK 3.4 简介 SEP4020 Linux SDK 3.4 简介 U-Boot1.3.3 介绍 Linux 内核及设备驱动介绍 文件系统介绍...15 第二章建立 LINUX 开发环境 虚拟机程序 Vmware Workstation 的安装 Fedora7 操作系统安装 新建虚拟机 在虚拟机中安装 Fedora7 操作系统 安装 Vmware Tools 安装交叉编译工具 网络文件系统 (Network File System,nfs) 安装 开启 nfs 文件系统服务 主机端的 nfs 配置 开发板端的 nfs 配置...35 第三章内核裁剪及内核编译 内核裁剪 nandflash 驱动 网卡驱动 触摸屏驱动 RTC 驱动 Lcd 驱动 声卡驱动 SD 卡驱动 *5 键盘 PSAM 卡 USB Device 文件系统驱动 Epson 72v17 USB Host 驱动 Epson 72v17 USB Device 驱动 热敏打印机驱动 针式打印机驱动 磁条卡驱动 内核编译及镜像制作 内核编译 内核镜像制作...64 第四章 SEP4020 Linux 驱动程序开发简介...66 TEL: FAX: 技术社区 : -3-

4 4.1 Linux 驱动介绍 Linux 驱动的框架 Linux 驱动简介 Linux 设备驱动程序结构 Linux 内核模块 编写 Hello Module 源代码 编译 Hello Module 源代码 把 HelloModule 下载到开发板并安装使用 Linux 字符驱动程序的设计 编写流水灯驱动程序源码 : 编译流水灯驱动源代码 下载流水灯模块到开发板上运行...87 第五章 SEP4020 的 HAL 层的应用 硬件抽象层的介绍 HAL 层的框架 HAL 层的内容介绍 GPIO 口使用 外部中断的使用 硬件抽象层的实际应用 键盘 HAL 层的建立 键盘驱动的更改 HAL 层的移植...96 第六章 SEP4020 Linux 驱动程序说明 SEP4020 Linux 操作系统硬件资源分配表 字符型驱动的设备号列表 字符型设备驱动 *5 键盘驱动 硬件原理图 驱动源码位置 内核编译相关选项 应用程序接口与程序样例 : RTC 实时时钟驱动 硬件原理图 驱动源码位置 内核编译相关选项 应用程序接口与程序样例 触摸屏驱动 硬件原理图 驱动源码文件位置 内核编译相关选项 应用程序接口与程序样例 PSAM 卡驱动 内置 PSAM 卡驱动 TEL: FAX: 技术社区 : -4-

5 硬件原理图 驱动源码位置 内核编译相关选项 应用程序接口与程序样例 外扩 PSAM 卡驱动 硬件原理图 驱动源码位置 内核编译相关选项 应用程序接口与程序样例 LCD 驱动 硬件原理图 驱动源码位置 内核编译相关选项 应用程序接口 IIS 音频驱动 硬件原理图 驱动源码位置 内核编译相关选项 应用程序接口 串口驱动 硬件原理图 驱动源码位置 内核编译相关选项 应用程序接口与程序样例 热敏打印机驱动 : 硬件原理图 : 驱动源码位置 : 内核编译相关选项 : 应用程序接口与程序样例 : 针式打印机驱动 : 硬件原理图 : 驱动源码位置 : 内核编译相关选项 : 应用程序接口与程序样例 : 磁条卡读卡器驱动 硬件原理图 驱动源码位置 内核编译相关选项 应用程序接口 射频卡驱动 硬件原理图 : 驱动源码位置 : 内核编译相关选项 : TEL: FAX: 技术社区 : -5-

6 应用程序接口与程序样例 SEP4020 Linux 块设备驱动 NANDFLASH 卡驱动 硬件原理图 驱动源码位置 内核编译相关选项 应用程序接口与程序样例 SD 卡驱动 硬件原理图 驱动源码位置 内核编译相关选项 应用程序接口与程序样例 USB device 驱动 硬件原理图 驱动源码位置 内核编译相关选项 应用程序接口与程序样例 S1R72V17 USB device 驱动 硬件原理图 驱动源码位置 内核编译相关选项 应用程序接口与程序样例 S1R72V17 USB-HOST 驱动 硬件原理图 驱动源码位置 内核编译相关选项 USB-HOST 使用方法 NOR flash 驱动 硬件原理图 驱动源码位置 内核编译相关选项 挂载分区演示 SEP4020 Linux 网络设备驱动 M 以太网硬件原理图 驱动源码文件位置 内核编译相关选项 网络应用程序接口与样例 什么是 Socket Socket 建立 数据传输 结束传输 Socket 编程实例 GPIO 通用驱动 TEL: FAX: 技术社区 : -6-

7 6.6.1 驱动源码位置 内核编译相关选项 应用程序接口 STN 驱动 硬件原理图如下 : 驱动源码位置 内核编译相关选项 应用程序接口与程序样例 第七章 Linux 应用程序开发 Linux 应用程序快速入门 编写源代码 helloworld.c 编译 helloworld.c 运行 helloworld 程序 MiniGUI 程序开发简介 MiniGUI 交叉编译过程 交叉编译的准备工作 MiniGUI 的安装与配置过程 MiniGUI 的移植 tslib 移植到 SEP SNMP( 简单网络协议 ) 程序开发 SNMP 基本知识 SNMP 的管理模型 SNMP 报文种类 开发实现 自定义模块 get 与 set 实现 trap 实现 CGI 应用程序开发简介 CGI 的定义 CGI 的功能 CGI 的处理过程 CGI 与 WebServer 信息传输与数据交换过程 CGI 常用环境变量及分类 CGI 编程实例 Sqlite 运行在 arm 上的简单介绍 PC 机编译安装 交叉编译 sqlite tar.gz 库文件 在 ARM 板上运行 sqlite 如何在 Linux 下用 C/C++ 语言操作数据库 sqlite 说明 开始 GPRS 程序开发简介 简介 串口设置 TEL: FAX: 技术社区 : -7-

8 7.6.3 Sim300 模块简易 at 指令说明 波特率设置 一些常用的 at 命令 拨打电话 发送英文短信 在 at command 模式下连接 tcp Linux 下应用程序参考 CDMA 程序开发 硬件说明 串口设置 eden800 模块简易 at 指令说明 设置模块速率 控制回显 语音呼叫 tcp 连接 基于 at 命令的发送方式拨号连接 API 接口说明 Linux 下应用程序参考 HDLC 模块 HDLC 简介 HDLC 中常用的操作方式 HDLC 模块硬件介绍 PSAM 应用说明 文件结构 主控文件 (Master File,MF) 专用文件 (Dedicated File,DF) 基本文件 (Elementary File,EF) 通讯协议 PSAM 卡命令格式 常用命令与应答编码 工作原理 MAC 加密应用 超时机制 FSK 应用说明 附录 GNU 通用公共授权 ( 简体中文翻译版 ) 导言 条款和条件 定义 源代码 基本的许可 保护用户的合法权利不受反破解法侵犯 发布完整副本 发布修改过的源码版本 TEL: FAX: 技术社区 : -8-

9 6. 发布非源码形式的副本 附加条款 终止授权 获取副本不需要接受本授权 下游接收者的自动授权 专利权 不要放弃别人的自由 和 GNU Affero 通用公共授权一起使用 本授权的修订版 免责申明 责任范围 第 15 和 16 节的解释 条款和条件结束 TEL: FAX: 技术社区 : -9-

10 第一章 SEP4020 Linux SDK 3.4 简介 1.1 SEP4020 Linux SDK 3.4 简介 SEP4020 Linux SDK 3.4 是基于南京博芯公司推出的系列开发板的一个包含 bootloader,linux 内核, 文件系统的源码开发包, 本文档将基于 SDK3.4 源码包, 从以下几个方面来详细介绍 SDK 及其使用方法 : SEP4020 Linux SDK 3.4 简介 Linux 开发环境的建立 内核裁剪及编译 简单驱动开发介绍及已有驱动说明 基于 SEP4020 Linux SDK 3.4 的应用程序开发目前 SEP4020 Linux SDK 3.4 所支持的开发平台有 UB4020MBT(V1.1), UB4020EVB(V1.2-V1.5),EPOS 平台 SEP4020 Linux SDK 3.4 包含三个部分 : (1) 基于 SEP4020 的 U-Boot; (2) 基于 SEP4020 的 Linux 内核 (3) 基于 UB4020MBT 开发板的文件系统 注意 :( 内核中包含了所支持开发板的所有驱动, 不同的硬件平台之间驱动不能混用, 使用前请核实该驱动是否使用您使用的硬件平台, 具体请参考 1.3 节中的驱动硬件平台对应表 ); 1.2 U-Boot1.3.3 介绍 U-Boot 是由德国的工程师 Wolfgang Denk 从 8XXROM 代码发展而来的, 它支持很多处理器, 比如 PowerPC ARM MIPS 和 x86 目前,U-Boot 源代码在 sourceforge 网站的社区服务器中,Internet 上有一群自由开发人员对其进行维护和开发, 它的项目主页是 U-Boot 的最新版本源代码可以在 Sourceforge 的 CVS 服务器中匿名获得 在 SEP4020 Linux SDK 3.4 使用的是 U-Boot 1.3.3,U-Boot 的主要作用是完成对开发板的硬件配置 ( 系统主频,SDRAM 参数, 串口, 以太网口 ) 以及 TEL: FAX: 技术社区 : -10-

11 代码的搬运和系统引导, 支持 zimage 的加载 关于 U-Boot 的一些命令和具体的 使用请参考用户手册 U-Boot1.3.3 源码包介绍 : 与 SEP4020 微处理器相关代码位置 :./cpu/sep4020/ start.s: 上电执行, 调用 cpu_init_crit(star.s) 初始化时钟频率及串口波特率, 调用 lowlevel_init(./board/prochip/ lowlevel_init.s) 初始化 EMI; serial.c: 串口代码,serial_setbrg 函数根据头文件 (./include/configs/ub4020.h) 设置波特率 ; interrupts.c: 中断处理,U-Boot 中可以不使用中断 (SEP4020 发布版未使能中断 ) 该文件另外一个重要的功能是通过硬件 Timer 实现精确延时 ; ether.c: 以太网相关函数, 包括以太网初始化 收发数据包 ; cpu.c:cpu 相关函数, 包括 RTC 设置 Reset 函数等 ; 与开发板相关代码位置 :./board/prochip/ common/flash.c:norflash 相关代码, 包括 NorFlash 识别 擦除 编程等操作 ; UB4020/UB4020.c: 板级初始化, 包括 NorFlash 保护初始化 NandFlash 初始化 以太网 MAC PHY 初始化及部分环境变量的初始化 ; UB4020/u-boot.lds: 链接信息 ; UB4020/dm9161.c: 以太网 PHY 相关函数, 包括初始化等操作 ; UB4020/ lowlevel_init.s: 主要是 SDRAM 初始化, 参见 start.s 说明 其它移植需要改动的文件./common/ cmd_nand.c:nandflash 操作相关函数 ;./include/configs/ub4020.h: 最重要的头文件, 所有配置信息均在该文件内 ;./include/arm-asm/arch-sep4020/hardware.h: 部分板级定义 ;./include/arm-asm/arch-sep4020/hardware.h:cpu 寄存器定义 1.3 Linux 内核及设备驱动介绍 Linux 2.6 在内核主体中加入了提高中断性能和调度响应时间的改进, 其中有三个最显著的改进 : 采用可抢占内核 更加有效的调度算法以及同步性的提高 TEL: FAX: 技术社区 : -11-

12 在嵌入式领域,Linux 2.6 除了提高其实时性能, 系统的移植更加方便, 同时添加了新的体系结构和处理器类型 包括对没有硬件控制内存管理方案的 MMU-less 系统的支持, 可以支持大容量内存模型 微控制器, 同时还改善了 I/O 子系统, 增添更多的多媒体应用功能 因此在 SDK3.4 中使用的 Linux 内核版本是 Linux Linux 源码包介绍 : 与 SEP4020 微处理器相关代码位置 : /linux/arch/arm/mach-sep4020 文件夹下是有关处理器架构的核心代码 : 4020.c > 系统启动配置 ; mm.c > 处理器内存静态映射 ; device.c > 注册平台设备 ; irq.c > 处理器中断注册 ; time.c > 注册系统时钟 ; clock.c > 系统时钟的相关操作函数 /linux/include/asm-arm/arch-sep4020 文件夹下是有关处理器和平台架构的所有头文件, 其中最重要的文件是 hardware.h hardware.h 中包括了所有寄存器实地址的定义, 静态映射后虚地址的定义, 系统主频等 其余文件主要和系统有关, 这里暂不介绍, 用户如有兴趣可参考相关书籍 与平台设备驱动相关代码位置 : 关于 evb 开发板驱动代码的位置主要分布在 /linux/drivers 文件夹下, 有一个例外, 音频驱动在 /linux/oss 文件夹下, 对每个驱动的具体说明分析请参考第四章 SEP4020 Linux 驱动程序分析, 代码位置分布如下 : 串口 : /linux/drivers/serial/8250.c NandFlash: /linux/drivers/mtd/nand/sep4020.c 以太网卡 : /linux/drivers/net/arm/sep_eth.c Lcd: /linux/drivers/video/sep4020fb.c 声卡 : /linux/sound/arm/oss/sep4020-uda1341.c RTC: /linux/drivers/char/sep4020_char/sep4020_rtc.c 5*5 键盘 : /linux/drivers/char/sep4020_char/sep4020_key.c 触摸屏 : /linux/drivers/char/sep4020_char/sep4020_tp.c PSAM 卡 : /linux/drivers/char/sep4020_char/sep4020_psam.c TEL: FAX: 技术社区 : -12-

13 SD 卡 : USB Device: /linux/drivers/mmc/sep_mci.c /linux/drivers/usb/gadget/ sep4020_udc.c 热敏打印机 :/linux/drivers/char/sep4020_char/thermal_printer.c 针式打印机 :/linux/drivers/char/sep4020_char/sep4020_printer.c 基于 Epson72v17 的 USB Host:/linux/drivers/usb/host/s1r72v17-hcd.c 基于 Epson72v17 的 USB Device:/linux/drivers/usb/gadget/s1r72v17_udc.c 磁条卡驱动 :/linux/drivers/char/sep4020_char/mg_card.c CDMA 驱动 :/linux/drivers/char/sep4020_char/sep4020_gpio.c HDLC 驱动 :/linux/drivers/char/sep4020_char/sep4020_hdlc.c 用于示例的 led 驱动 ;/linux/drivers/char/sep4020_char/sep4020_led.c 驱动 硬件平台对应表 :(Y 表示该硬件平台支持此驱动,N 表示相反 ) 硬件平台 UB4020EVB (V1.2-V1.4) UB4020MBT (V1.1) UB4020EVB (V1.5) EPOS 驱动 串口 Y Y Y Y NandFlash Y Y Y Y 以太网卡 Y Y Y Y LCD Y Y Y Y 声卡 Y Y Y Y RTC Y Y Y Y 5*5 键盘 Y Y Y Y 触摸屏 N( 需特定 B Y Y Y 版支持 ) PSAM 卡 Y Y Y Y SD 卡 Y Y Y Y USB Device Y Y Y Y TEL: FAX: 技术社区 : -13-

14 热敏打印 N N N Y 针式打印 N N N Y 72v17 USB Host N N Y Y 72v17 USB N N Y Y Device CDMA N N N Y HDLC N N N Y 磁条卡 N N N Y TEL: FAX: 技术社区 : -14-

15 1.4 文件系统介绍 在 SDK3.4 中提供的文件系统集成了大量的应用和演示代码, 用户可直接将其在 Linux 主机上解压, 并将其作为网络文件系统使用, 也可以使用 mkcramfs 工具将其做成 cramfs 格式的文件系统, 烧录在开发板端使用, 关于这一部分请参考用户手册 文件系统源码包介绍 : /bin 目录下是常用的命令 ( 包括 boa,snmp); /dev 目录下是所有设备 ; /etc 目录下是系统的配置文件 ; /lib 目录下是所有的库文件 (glib,tslib,miniguilib); /sbin 目录下是一些高级命令 ; /usr 目录下存放了用户常用的文件, 在我们这里 minigui 的配置文件就放在此处 ; /tmp 目录是临时文件夹, 即定位在 SDRAM 中的, 断电后该文件夹内的所有文件将会消失 ; /demo 和 /minigui-demo 这两个文件夹集中了所有的应用程序示例 : /minigui-demo 目录下包含了 minigui 的示例程序, 其中 minigui-simple 文件夹下是简单的控件例子,minigui-mde 文件夹下是综合实例 /demo 目录下是除了 gui-demo 外所有的应用程序示例, 包括 : 12864lcd-demo(128*64 灰度屏 ) inter-psam(evb 板的内置 psam 卡 ) boa key-demo( 键盘 ) cdma(cdma 模块 ) Magnetic card-demo( 磁条卡应用程序 ); mp3-demo(mp3 播放应用程序 ); dot matrix printer-demo( 针式打印机应用程序 ); printer-demo( 热敏打印机应用程序 ); dot matrix printer-demo(special) RCF_demo( 射频卡 ) expsam-demo(epos)(pos 版外扩 PSAM 卡 ) snmp-demo(snmp); TEL: FAX: 技术社区 : -15-

16 fsk-demo(epos)(fsk) sqlite3 gpio_led_demo( 通用 GPIO 口驱动演示 ) thermal_printer-demo(epos)( 热敏打印机 ) gprs(gprs) tslib-demo( 触摸屏校准应用程序 ); hdlc_demo video-demo 其中针式打印机应用程序, 磁条卡应用程序, 热敏打印机应用程序需特定打印机平台支持, 普通 evb,mbt 平台不支持此功能, 因此这里暂不具体介绍 /tslib-demo 目录下是 tslib 的校准程序, 在第一次使用触摸屏时建立, 首先运行一下这个程序 (ts_calibrate) 并按照屏幕显示光标进行操作, 之后使用无需运行 没有使用触摸屏不需跑此程序 ; /mp3-demo 目录下是 mp3 的运行程序, 由于在其他存储设备 ( 网络, nandflash) 读取速度的问题, 建议用户在运行音频程序的时候先把音频源拷贝至 sdram 中, 即 /tmp; /snmp-demo 下是简单网络管理协议的应用程序, 具体的使用可参考用户手册 注意 : 文件系统启动脚本中已添加自动更新 rtc 时间, 设备节点命令, 用户不需再手动创建节点等操作 TEL: FAX: 技术社区 : -16-

17 第二章建立 LINUX 开发环境 本章从在 PC 机上安装 VM 虚拟机开始, 详细介绍了如何建立 Linux 开发环 境 在整个演示过程中我们所使用的 Linux 版本均是 Fedora7, 用户如果使用其 他版本的 Linux 操作系统可能会导致错误 2.1 虚拟机程序 Vmware Workstation 的安装 在我们提供的光盘中找到 VMware-workstation 安装程序, 双击安装 ( 在安装的过程中可能会比较慢, 请耐心等待 ) 在点击 NEXT 后, 选择 Typical ( 典型安装 ), 然后一路 NEXT 直到 Finish, 重启计算机 双击安装完成后的 VM 文件, 弹出如图 2.1 的对话框 图 2.1 选择 NO 点击 OK, 完成安装 在打开的 VM 下选择 Help->Enter Serial Number, 打开如图 2.2, 输入许可证号 用户名和公司名, 选择 OK, 完成注册 TEL: FAX: 技术社区 : -17-

18 图 Fedora7 操作系统安装 新建虚拟机 在打开的 VM 下选择 File->New->Virtual Machine 打开图 2.3 的对话框 图 2.3 选择两次 下一步 打开如图 2.4 的对话框 ( 并按照图 2.4 进行选择 ) TEL: FAX: 技术社区 : -18-

19 如图 2.5 图 2.4 点击 下一步, 填写虚拟机名称和保存的位置 ( 用户按自己的实际情况填写 ) 2.6 图 2.5 点击 下一步 选择网络类型, 选择默认的 Use bridge networking ( 桥接 ) 如图 TEL: FAX: 技术社区 : -19-

20 图 2.6 点击 下一步, 选择 Disk Size 为 16GB 如图 2.7 所示 图 2.7 点击 完成 后的界面应如下图 2.8 所示 图 2.8 TEL: FAX: 技术社区 : -20-

21 在点击 Start 之前, 我们还要对内存进行配置 ( 我们这里配置为 740MB, 可 根据你电脑的配置进行适当调整 ) 如图 2.9 图 在虚拟机中安装 Fedora7 操作系统 给 Cdrom 插入镜像文件 : 双击 CD-ROM, 然后选择镜像文件 ( 图 2.10) 图 2.10 点击 Start 可能会出现图 2.11 的提示信息, 我们点 Yes 忽略 TEL: FAX: 技术社区 : -21-

22 图 2.11 然后就进入了 Fedora 的安装界面 ( 如下图 2.12 所示 ) 在图 2.12 选择第一个 选项, 按回车确定 图 2.12 注意 : 细心的您可能会发现, 这个时候鼠标被锁定在虚拟机里面, 如果想回到 windows 下, 可以用组合键 Ctrl+Alt 接下来按列出的图片进行操作, 没有特别说明的操作表示 默认操作, 对选项不作任何修改, 直接点 下一步 在出现图 2.13 下用 TAB 键选择 SKIP, 然后选择 NEXT, 在图 2.14 的界面中选择语言为简体中文 TEL: FAX: 技术社区 : -22-

23 图 2.13 图 2.14 点击 Next 进入下面的图 2.15, 要求选择键盘的类型, 我们选择默认的 美 国英语式, 点 下一步 出在的对话框时选择 是 TEL: FAX: 技术社区 : -23-

24 在跳出下面的图 2.16 时后, 选择 是 图 2.15 图 2.16 然后时区的选择 亚洲 / 上海, 然后点 下一步, 出现下面的图 2.17, 要求用 户输入 根用户 口令, 该口令是用户以 root 用户登录系统时的密码 TEL: FAX: 技术社区 : -24-

25 图 2.17 在出现图 2.18 后, 将软件开发和网络服务器也选上, 后点 下一步 图 2.18 在出现图 2.19 后, 表示 Linux 进入安装过程中了, 整个过程大概需要 40 分 钟, 请用户耐心等待 图 2.19 TEL: FAX: 技术社区 : -25-

26 经过漫长的等待, 最后出现如下图 2.20, 就表示 Linux 已经顺利安装完成了 我们还不暂时还不能使用系统, 点击 重新引导, 还有一些常用的设置要完成 图 2.20 在重新引导后, 会出现如下的欢迎界面, 在 前进 两步之后, 将 防火墙 选 择 禁用 ( 图 2.21) 图 2.21 TEL: FAX: 技术社区 : -26-

27 直接按 前进, 一直到如下的界面出现时 选择 Do not send profile 按 前进 会弹出图 2.22 的对话框, 选择 No,do not send 图 2.22 以后系统会提示 创建用户, 我们这里直接以 root 用户登录, 不需要创建用户, 所以直接点 前进 出现声卡选项, 我们点完成 重新引导系统 在出现登录界面后, 在 用户名 后面输入 :root( 根用户 ), 按回车, 会提示输出 口令 ( 就是之前提示输入的密码 ) TEL: FAX: 技术社区 : -27-

28 2.2.3 安装 Vmware Tools 第一步 : 点击 VM->Install Vmware Tools, 出现以下的界面, 点击 Install 如图 2.23 图 2.23 第二步 : 在 Fedora 下双击 计算机, 在打开的文件下双击 CD-ROM 驱动器 出现如图 2.24, 有一个 RPM( 包管理器文件 ) 和一个压缩包 图 2.24 TEL: FAX: 技术社区 : -28-

29 第三步 : 双击 RPM 文件, 出现图 2.25 的 正在安装软件包 单击 应用 在弹 出的对话框中选择 无论如何都安装 图 2.25 第四步 : 在安装完成之后会有一个提示, 点击 OK 即可 当然, 我们也可以省去第 2-4 步, 而使用另一种方法来安装 VM Tools 首先, 将 RPM 文件拷到 /root 目录下, 然后将 Fedora 的 应用程序 -> 系统工具 -> 终端 打开, 在其中输入 rpm -ivh VMwareTools i386.rpm 如图 2.26 图 2.26 第五步 : 在 终端下依次输入 : cd /usr/bin 和./vmware-config-tools.pl 第六步 : 一路按回车, 直到出现分辨率选择时候, 为你的虚拟机选择适合的分辨率 ( 图 2.27), 完了之后, 重启虚拟机 ( 也可以在菜单系统 -> 首选项 -> 硬件 -> 屏幕分辨率中修改 ) TEL: FAX: 技术社区 : -29-

30 图 2.27 重启之后, 会发现分辨率变了, 而且鼠标不会被锁定的虚拟机里面了, 更好的是 Win-XP 下的文件可以直接拉到虚拟机里面, 这样使以后的开发更加方便 为了以后的方便, 我们还应该将 应用程序 -> 系统工具 -> 终端 也拉到桌面上来, 而不要每次还要找半天 2.3 安装交叉编译工具 1 首先, 下载一个源码包 :arm-linux-gcc tar.bz2 2 将源码包拷贝到根目录 / 下, 解压后确认目录为 : /usr/local/arm/3.4.1/ 3 添加环境变量到系统中: 打开 /etc/bashrc, 并在 bashrc 文件的最后一行添加 : export PATH=/usr/local/arm/3.4.1/bin:$PATH, 保存, 此时环境变量已经添入系统 4 只要在终端中输入 arm-linux-gcc -v, 会出现图 2.28 信息的话代表交叉编译工具已经安装成功, 如果没有图 2.28 信息, 再检查前面几步有没有出错 TEL: FAX: 技术社区 : -30-

31 图 网络文件系统 (Network File System,nfs) 安装 开启 nfs 文件系统服务 主机端的 nfs 配置 在 Fedora 下点击 系统 -> 管理 -> 网络, 双击你的网络配置, 选择静态设置 ip 地址, 填入你的 ip, 子网掩码和网关 ( 比如我的是 ; ; ), 如图 2.29 图 2.29 TEL: FAX: 技术社区 : -31-

32 点击 确认, 再点击 激活, 会跳出下面图 2.30, 再点击 是 图 2.30 在虚拟机下配置虚拟机的网卡 edit->virtual network setting->host virtual network mapping 添加一个真实的网卡 ( 即在第一个下拉菜单中选择一个已经存在的网卡 ), 并按 应用, 确认, 如图 2.31 图 2.31 编辑文件 /etc/exports 添加 nfs 目录的支持 : TEL: FAX: 技术社区 : -32-

33 /nfs (rw,sync,no_root_squash) 其中 是开发板的 IP; / nfs 表示 nfs 共享目录, 它可以作为开发板的根文件系统 ;rw 表示挂接此目录的客户机对该目录有读写的权力 ; no_root_squash 表示允许挂接此目录的客户机享有该主机的 root 身份, 保存 在终端下输入 setup ( 图 2.32) 将 系统服务 中的 netconsole,netplugd,nfs 服务选上 ( 按空格键选择 ) 并按 tab 确认 退出, 如图 2.33 图 2.32 TEL: FAX: 技术社区 : -33-

34 图 2.33 在终端中输入 service nfs restart ~]# service nfs restart 关闭 nfs mountd: [ 失败 ] 关闭 nfs 守护进程 : [ 失败 ] 关闭 nfs quotas: [ 失败 ] 关闭 nfs 服务 : [ 确定 ] 启动 nfs 服务 : [ 确定 ] 关掉 nfs 配额 : [ 确定 ] 启动 nfs 守护进程 : [ 确定 ] 启动 nfs mountd: [ 确定 ] [root@localhost ~]# 在根目录下添加 nfs 文件夹 ( 这个文件系统可在 网站上下到, 建议使用 full 版的 3.2 的 nfs), 文件结构如下 ( 图 2.34): TEL: FAX: 技术社区 : -34-

35 重启电脑, 主机端的 nfs 设置完成 图 开发板端的 nfs 配置 开发板端的配置比较简单, 主要是修改 bootargs 参数, 修改后的参数应为 : set bootargs root=/dev/nfs rw nfsroot= :/nfs ip= : : console=ttys0, mem=32mb 修改后敲入 save 命令, 将开发板和主机用直连网线相连接, 开启板子会看到已经把 nfs 文件系统挂载上去了 : ( 以上省略 ) IP-Config:Gateway not on directly connected network. Looking up port of RPC /2 on Looking up port of RPC /1 on VFS:Mounted root (nfs filesystem). Freeing init memory:120k nfs:server not responding,still trying nfs:server OK init started:busybox V1.9.2 ( :15:54 CST) starting pid 243,tty '':'/etc/init.d/rcs' *************************************************** SEP4020 ARM Linux (VERSION2.2) *************************************************** #mount all... #Starting mdev... starting pid 251,tty'':'/bin/sh' hwclock:can't open '/dev/misc/rtc':no such file or directory TEL: FAX: 技术社区 : -35-

36 /# 至此整个 nfs 配置完毕 如果使用 nfs 的时候, 发现错误为 unable to open an initial console, 如下图 : <6>eth0:Link now 10-HalfDuplex IP-Config:Guessing netmask IP-Config:Gateway not on directly connected network. Looking up port of RPC /2 on Looking up port of RPC /1 on VFS:Mounted root (nfs filesystem). Freeing init memory 116K Warning:unable to open an initial console. 请检查你的主机 /nfs 文件夹下是否有 console 这个文件, 如果没有, 请在终端下输入指令 : mknod /nfs/dev/console c 5 1 如果有时候发现网络文件系统不能用, 请依次检查主机端和开发板端配置, 一般问题都在里面 最后, 我们来看一下 nfs 文件系统, 它具有空间无限大 ( 内容是存储在主机上, 不受开发板存储大小的限制 ) 与开发板的交互方便 ( 内容是存储在主机上, 只要替换个主机文件夹 ) 的优点 下面是一些常见的 nfs 目录的介绍 : /bin 目录下是常用的命令 /dev 目录下是所有设备 /etc 目录下是系统的配置文件 /lib 目录下是所有的库文件 (glib,tslib,miniguilib) /sbin 目录下是一些高级命令 /usr 目录下存放了用户常用的文件 /tmp 是临时文件夹是临时文件夹, 断电后该文件夹内的所有文件将会消失 TEL: FAX: 技术社区 : -36-

37 第三章内核裁剪及内核编译 3.1 内核裁剪 1 拷贝一个已经移植好 sep4020 框架的内核 ( 目前最新版本 v3.4) 解压到根目录下 : 2 打开一个终端, 进入 linux 目录 ( 命令 :cd /linux) 如图 3.1 图 敲击命令 :make menuconfig 对内核进行配置 ( 图 3.2) 图 3.2 TEL: FAX: 技术社区 : -37-

38 主要驱动均分布在 Device Driver 目录下, 驱动分布及相应选项配置如下 : nandflash 驱动 Device Driver->Memory Technology Devices->Nand Flash Device Drivers->Support for Southeast University sep4020 如图 3.3 图 3.4 图 3.3 图 3.4 TEL: FAX: 技术社区 : -38-

39 3.1.2 网卡驱动 Device Driver->Network device support->ethernet(10 or 100Mbit)->SEP4020 Ethernet support( 图 3.5 图 3.6) 图 3.5 图 触摸屏驱动 Device Driver->Character devices->sep4020 char drivers->sep4020 char device->sep4020 touchpad driver 如图 3.7 图 3.8 TEL: FAX: 技术社区 : -39-

40 图 3.7 图 RTC 驱动 Device Driver->Character devices->sep4020 char drivers->sep4020 char device->sep4020 rtc driver, 如图 3.9 图 3.10 TEL: FAX: 技术社区 : -40-

41 图 3.9 图 Lcd 驱动 共有三个地方, 如图 3.11 图 3.12 图 3.13 Device Driver->Graphics support->sep *480 LCD support -> SEP *240 LCD support ( 根据不同分辨率选择, 只能选择一个, 不能同时选择 ) TEL: FAX: 技术社区 : -41-

42 图 3.11 Device Driver->Graphics support->console display driver-support 图 3.12 Device Driver->Graphics support->logo configuration TEL: FAX: 技术社区 : -42-

43 图 声卡驱动 Device Driver->Sound->Sound card support->open sound system->sep4020 UDA1341 driver 如图 3.14 图 3.15 图 3.14 图 3.15 TEL: FAX: 技术社区 : -43-

44 3.1.7 SD 卡驱动 Device Driver->MMC/SD Card support->sep4020 Multimedia Card Interface support 如图 3.16 图 *5 键盘 Device Driver->Character devices->sep4020 char drivers->sep4020 char device->sep4020 5*5 key driver 如图 3.17 图 3.18 图 3.19 图 3.20 图 3.17 TEL: FAX: 技术社区 : -44-

45 图 3.18 图 3.19 TEL: FAX: 技术社区 : -45-

46 图 PSAM 卡 Device Driver->Character devices->sep4020 char drivers->sep4020 char device->sep4020 psam card driver(for epos board) 如图 3.21 图 3.22 图 3.23 图 3.24 TEL: FAX: 技术社区 : -46-

47 图 3.21 图 3.22 图 3.23 TEL: FAX: 技术社区 : -47-

48 图 USB Device Device Driver->USB support-> USB Gadget Support->File-backed storage Gadget( 图 图 3.28) 图 3.25 TEL: FAX: 技术社区 : -48-

49 图 3.26 图 3.27 TEL: FAX: 技术社区 : -49-

50 了 图 3.28 把如图中的 * 和 M 相应的都选上就能将 4020 本身的 usb device 编译进内核 文件系统驱动 Linux 能兼容各种形式的文件系统, 包括 yaffs cramfs nfs VFAT fs MSDOS fs ext2(ext3) proc sys, 这也是 linux 的一个很重要的特色之一 下面是我们在嵌入式开发中常用到的一些文件系统形式 : Yaffs(for nand, 是个可读可写的文件系统 ), 进入 File system, 选项配置如图 3.29 图 3.29 TEL: FAX: 技术社区 : -50-

51 Cramfs(for nand, 是个可读的文件系统, 不可写 ) 进入 File system->miscellaneour filesystems, 选项配置如图 3.30 Nfs( 网络文件系统 ) 图 3.30 进入 File system->network File systems, 选项配置如图 3.31: 图 3.31 TEL: FAX: 技术社区 : -51-

52 到 ) Vfat fs MSdos fs( 能够支持微软的一些文件格式, 在挂载 u 盘等东西时需要用 进入 File system->dos/fat/nt Filesystem 图 3.32 图 3.32 proc sys 文件系统 proc 文件系统是一个伪文件系统, 它只存在内存当中, 而不占用外存空间 它以文件系统的方式为访问系统内核数据的操作提供接口 sysfs 是 Linux 内核中设计较新的一种虚拟的基于内存的文件系统, 它的作用与 proc 有些类似, 但除了与 proc 相同的具有查看和设定内核参数功能之外, 还有为 Linux 统一设备模型作为管理之用 进入 File system->pseudo filesystems 如图 3.33 图 Epson 72v17 USB Host 驱动 /driver/usb/host/sir72xxx TEL: FAX: 技术社区 : -52-

53 图 3.34 图 3.35 TEL: FAX: 技术社区 : -53-

54 图 3.36 TEL: FAX: 技术社区 : -54-

55 Epson 72v17 USB Device 驱动 /linux/drivers/usb/gadget/ sep4020_udc.c 图 3.37 图 3.38 TEL: FAX: 技术社区 : -55-

56 图 3.39 图 热敏打印机驱动 Device Driver->Character devices->sep4020 char drivers->sep4020 char device->sep4020 Thermal Printer driver (for special board!) TEL: FAX: 技术社区 : -56-

57 图 3.41 图 3.42 TEL: FAX: 技术社区 : -57-

58 图 3.43 图 3.44 TEL: FAX: 技术社区 : -58-

59 针式打印机驱动 Device Driver->Character devices->sep4020 char drivers->sep4020 char device->sep4020 Dot-Matrix Printer driver (for special board!) 图 3.45 图 3.46 TEL: FAX: 技术社区 : -59-

60 图 3.47 图 3.48 TEL: FAX: 技术社区 : -60-

61 磁条卡驱动 Device Driver->character devicest->sep4020 char device->sep4020_mgcd driver 图 3.49 图 3.50 TEL: FAX: 技术社区 : -61-

62 图 3.51 TEL: FAX: 技术社区 : -62-

63 图 内核编译及镜像制作 内核编译 保存你的修改, 在终端中输入 make 命令, 开始编译内核 ( 图 3.53) TEL: FAX: 技术社区 : -63-

64 图 3.53 内核已经成功编译完成, 具体位于 /linux/arch/arm/boot/zimage 注意事项 : (1) Make menuconfig 有很强的关联性, 不准确的多选或少选一些配置会导致系统的不正确, 因此不建议用户随意修改内核配置, 应该严格按照手册修改 ; (2) * 是表示编译进内核,M 表示编译成 module 形式 ; (3) 一些系统常用的配置这里不做阐述, 如系统类型, 串口, 控制台等常用驱动 ; (4) 内核中存在一些非 mbt 平台驱动, 如打印机,usb, 在选择这些驱动时请确认驱动是否能用在你使用的平台上 ; (5) 用户若不小心改动了内核配置, 用户可在 /linux 根目录下输入命令 : make sep4020_defconfig 来恢复默认配置 内核镜像制作 刚刚这样生成的内核还是不能直接给我们的板子使用, 为了让 U-Boot 能准确认出我们的内核, 必须给我们的内核在进行一条命令, 在执行这条命令前首先要将 mkimage 这个程序拷贝到 /bin 目录下, 这个程序在 上也能下到 ( 可能直接拷进去会出现权限不够的提示, 在终端下输入命令 chmod 777 /bin/mkimage) 然后在刚才打开的终端中输入命令 : mkimage -n "Kernel " -A arm -O linux -T kernel -C none -a 30007fc0 -e d./arch/arm/boot/zimage vmlinux.img mkimage 各参数意义如下 :( 可在终端下输入 mkimage help 查询 ) 图 3.54 TEL: FAX: 技术社区 : -64-

65 输入命令后的结果如图 3.55: 图 3.54 图 3.55 这样在 /linux 根目录下生成的 vmlinux.img 就是我们真正能让板子使用的内核了, 可以放到 tftp 服务器目录下使用了 TEL: FAX: 技术社区 : -65-

66 第四章 SEP4020 Linux 驱动程序开发简介 在 4.2 小节, 我们介绍最简单的 HelloModule 驱动程序模块, 它只是从串口输出一些信息, 并未对应板上的硬件进行操作, 后面的几个例子都是和硬件密切相关的实际驱动, 在嵌入式 Linux 系统中, 大部分的硬件都需要类似的驱动才能操作, 比如触摸屏 网卡 音频等, 在这里我们介绍的是一些简单典型的例子 -- 流水灯, 相信大家对这个例子不会陌生的吧, 在这里我想通过这个简单驱动的讲解让大家大概了解下在 linux 系统中怎么开发硬件, 怎么让硬件更好的为自己工作, 实际上复杂的驱动都有参考代码, 不必从头写驱动 4.1 Linux 驱动介绍 Linux 驱动的框架 内核 模块 设备注册 module_init () 应用程 序 设备功能 驱动程序 硬件设备 设备卸载 module_exit () 图 4.1 linux 驱动框架结构图在操作系统里, 对用户而言, 设备驱动程序隐藏了设备的具体细节 对于各种不同的设备, 如调制解调器,USB 扫描仪, 打印机等, 从用户的角度看, 它们都是特殊化的文件, 以用同样的 Read,Write 等操作, 完成对不同设备的访问 而驱动程序在特殊的设备和一般的用户间起了桥梁的作用 用户进程的下层是设备无关的软件, 在 Linux 中设备无关软件的大部分功能 TEL: FAX: 技术社区 : -66-

67 由文件系统去完成, 执行适用于所有设备的常用 I/O 功能, 向用户进程提供一个统一的接口 当用户进程发出 I/O 请求时,Linux 把请求的处理权限放在文件系统, 文件系统通过设备驱动程序提供的接口再把任务下放到驱动程序, 驱动程序根据需要对设备控制器进行操作, 设备控制器再去控制设备自身 这样通过逐层隔离,Linux 对用户进程基本上屏蔽掉了设备的各种硬件特性 设备控制器对设备自身的控制是电气工程师的职责范围, 操作系统对 I/O 设备的管理只是通过文件系统和设备驱动程序来完成 在 Linux 中, 设备驱动程序应完成的主要功能为 : 对设备进行初始化 ; 设备使用完成后对设备进行相应清理工作 ; 从设备接收数据并将之送回内核 ; 将数据从内核传送至设备 ; 检测和处理设备出现的错误 通常 Linux 驱动程序接口分为如下四层 : 应用程序进程与内核的接口 ; 内核与文件系统的接口 ; 文件系统与设备驱动程序的接口 ; 设备驱动程序与硬件设备的接口 Linux 内核需要访问两类主要设备 : 字符设备和块设备 与此相关主要有两类设备驱动程序, 字符设备驱动程序和块设备驱动程序 字符设备是最简单的, 如鼠标 键盘 甚至自己设计的 I/O 卡等 块设备的读写一般要缓存支持, 并可随机存取 ( 字符设备则不需要 ), 它主要包括硬盘 光驱等存贮设备 两者的主要差异是 : 与字符设备有关的系统调用几乎直接和驱动程序的内部功能结合在一起 而读写块设备则主要和快速缓冲存储区打交道 只有需要完成实际的输入 / 输出时, 才用到块设备驱动程序 Linux 的设备由一个主设备号 (major number) 和一个次设备号 (minor number) 标识 主设备号唯一标识了设备类型, 即设备驱动程序类型, 它是块设备表或字符设备表中设备表项的索引 次设备号仅由设备驱动程序解释, 用于识别同类设备中,I/O 请求所涉及到的那个设备 TEL: FAX: 技术社区 : -67-

68 应用程序 VFS 字符设备驱动 文件系统 (ext2,yaffs ) 字符设 其他设备驱动 其他设备 图 4.2 设备 驱动 文件系统 应用程序之间的调用关系 Linux 驱动简介 当引导系统时, 内核调用每一个驱动程序的初始化函数 它的任务之一是将这一设备驱动程序使用的主设备号通知内核 ; 同时, 初始化函数还将驱动程序中的函数地址结构的指针送给内核 内核中有两张表 一张表用于字符设备驱动程序, 另一张用于块设备驱动程序 这两张表用来保存指向 file_operations 结构的指针, 设备驱动程序内部的函数地址就保存在这一结构中 内核用主设备号作为索引访问 file_operations 结构, 因而能访问驱动程序内的子程序 对于字符设备来说,file_operations{ 是唯一的函数接口 此结构定义为 : #include<linux/fs.h> struct file_operations{ int (*lseek) (struct inode *inode,struct file *filp,off_to ff,int pos); /* 设备定位 */ int (*read) (struct inode *inode,struct file *filp,char *buf,int count); /* 设备读 */ int (*write) (struct inode *inode,struct file *filp,char *buf,int count); /* 设备 TEL: FAX: 技术社区 : -68-

69 写 */ int (*readdir) (struct inode *inode,struct file *filp,struct dirent *dirent,int count); int (*select) (struct inode *inode,struct file *filp,int sel_type,select_table *wait); int (*ioctl) (struct inode *inode,struct file *filp,unsigned int cmd,unsigned int arg); /*I/O 控制 */ int (*mmap) (void); int (*open) (struct inode *inode,struct file *filp); /* 设备打开 */ void (*release) (struct inode *inode,struct file *filp); /* 设备关闭 */ int (*fsync) (struct inode *inode,struct file *filp); ; 在结构 file_operations 里, 指出了设备驱动程序所提供的入口点位置, 分别是 : (1) lseek: 移动文件指针的位置, 显然只能用于可以随机存取的设备 (2) read: 进行读操作, 参数 buf 为存放读取结果的缓冲区,count 为所要读取的数据长度 返回值为负表示读取操作发生错误, 否则返回实际读取的字节数 (3) write: 进行写操作, 与 read 类似 (4) readdir: 取得下一个目录入口点, 只有与文件系统相关的设备驱动程序才使用 (5) select: 进行选择操作, 如果驱动程序没有提供 select 入口,select 操作将会认为设备已经准备好进行任何的 I/O 操作 (6) ioctl: 进行读 写以外的其它操作, 参数 cmd 为自定义的的命令 (7) mmap: 用于把设备的内容映射到地址空间, 一般只有块设备驱动程序使用 (8) open: 打开设备准备进行 I/O 操作 返回 0 表示打开成功, 返回负数表示失败 如果驱动程序没有提供 open 入口, 则只要 /dev/driver 文件存在就认为打开成功 (9) release: 即 close 操作 设备驱动程序所提供的入口点, 在设备驱动程序初始化的时候向系统进行登记, 以便系统在适当的时候调用 Linux 系统里, 通过调用 register_chrdev 向系统注册字符型设备驱动程序 register_chrdev 定义为 : #include<linux/fs.h> TEL: FAX: 技术社区 : -69-

70 #include<linux/errno.h> int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops); 在 register_chrdev() 函数中, 如果参数 major 为 0, 则系统动态为其分配一个设备号 如果 major 大于 0 则按照 major 给出的主设备号给其分配一个设备号 设备号分配成功后,register_chrdev() 调用 cdev_alloc() 分配一个 cdev 结构, 并进行初始化, 建立 cdev 和 file_operations 之间的连接 之后调用 cdev_add() 向系统注册字符设备 对于它的返回值, 在注册成功时, 如果参数 major 为 0 则返回动态申请的设备号, 否则返回 0 在注册失败时返回错误码 初始化部分一般还负责给设备驱动程序申请系统资源, 包括内存 中断 时钟 I/O 端口等, 这些资源也可以在 open 子程序或别的地方申请 在这些资源不用的时候, 应该释放它们, 以利于资源的共享 在 Linux 系统里, 对中断的处理是属于系统核心的部分, 因此如果设备与系统之间以中断方式进行数据交换的话, 就必须把该设备的驱动程序作为系统核心的一部分 设备驱动程序通过调用 request_irq 函数来申请中断, 通过 free_irq 来释放中断 它们的定义为 : #include<linux/sched.h> int request_irq (unsigned int irq,void (*handler) (int irq,void dev_id, structpt_regs *regs), unsigned long irqflags,const char *devname,void *dev_id); void free_irq (unsigned int irq,void *dev_id); 参数 irq 表示所要申请的硬件中断号 handler 为向系统登记的中断处理子程序, 中断产生时由系统来调用, 调用时所带参数 irq 为中断号,dev_id 为申请时告诉系统的设备标识,regs 为中断发生时寄存器内容 devname 为设备名, 将会出现在 /dev 文件里 irqflag 是申请时的选项, 它决定中断处理程序的一些特性, 其中最重要的是中断处理程序是快速处理程序 (irqflag 里设置 SA_INTERRUPT) 还是慢速处理程序 ( 不设置 SA_INTERRUPT) 快速处理程序运行时, 所有中断都被屏蔽, 而慢速处理程序运行时, 除了正在处理的中断外, 其它中断都没有被屏蔽 在 Linux 系统中, 中断可以被不同的中断处理程序共享, 这要求每一个共享此中断的处理程序在申请中断时在 irqflags 里设置 SA_SHIRQ, 这些处理程序之间以 dev_id 来区分 如果中断由某个处理程序独占, 则 dev_id 可以为 NULL TEL: FAX: 技术社区 : -70-

71 request_irq 返回 0 表示成功, 返回 -INVAL 表示 irq 无效或 handler=null, 返回 -EBUSY 表示中断已经被占用且不能共享 和中断有关的数据结构 : struct irqaction { irq_handler_t handler; /* 指向中断服务程序 */ unsigned long flags; /* 中断标志 */ unsigned long mask; /* 中断掩码 */ const char *name; /* I/O 设备名 void *dev_id; /* 设备标识 */ struct irqaction *Next; /* 指向下一个描述符 */ int irq; /* IRQ 线 */ struct proc_dir_entry *dir; /* 指向 IRQn 相关的 /proc/irq/n 目录的描述符 */ ; 作为系统核心的一部分, 设备驱动程序在申请和释放内存时不是调用 malloc 和 free, 而代之以调用 kmalloc 和 kfree, 它们被定义为 : #include<linux/kernel.h> void *kmalloc (unsigned int len,intpriority); void kfree (void *obj); 参数 len 为希望申请的字节数,obj 为要释放的内存指针 priority 为分配内存操作的优先级, 即在没有足够空闲内存时如何操作, 一般用 GFP_KERNEL 与中断和内存不同, 使用一个没有申请的 I/O 端口不会使 CPU 产生异常, 也就不会导致诸如 segment ation fault" 一类的错误发生 任何进程都可以访问任何一个 I/O 端口 此时系统无法保证对 I/O 端口的操作不会发生冲突, 甚至会因此而使系统崩溃 因此, 在使用 I/O 端口前, 也应该检查此 I/O 端口是否已有别的程序在使用, 若没有, 再把此端口标记为正在使用, 在使用完以后释放它 这样需要用到如下几个函数 : int check_region (unsigned int start,unsigned long n); void request_region (unsigned int start,unsigned long n); void release_region (unsigned int start,unsigned long n); 调用这些函数时的参数为 :start 表示所申请的 I/O 端口的起始地址 ;n 为所要申请的从 from 开始的端口数 ; check_region 返回 0 表示 I/O 端口空闲, 否则为正在被使用 TEL: FAX: 技术社区 : -71-

72 request_region 申请 I/O 端口使用完成后, 使用 release_region 函数将他们归还给系统 在申请了 I/O 端口之后, 就可以如下几个函数来访问 I/O 端口 : #include<asm/io.h> inline unsigned int inb(unsigned short port); inline unsigned int inb_p(unsigned short port); inline void outb(char value,unsigned shortport); inline void outb_p(char value,unsigned short port); 其中 inb_p 和 outb_p 插入了一定的延时以适应某些慢的 I/O 端口 Linux 设备驱动程序结构 Linux 设备驱动程序的代码结构大致可以分为如下几个部分 : 驱动程序的注册与注销 设备的打开与释放 设备的读写操作 设备的控制操作 设备的中断和轮询处理 一个最简单字符驱动程序, 由下面 5 个函数和 1 个结构体就可组成 static int my_open(struct inode * inode, struct file * filp) { 设备打开时的操作 static int my_release(struct inode * inode, struct file * filp) { 设备关闭时的操作 static int my_write(struct file *file, const char * buffer, size_t count, loff_t * ppos) { 设备写入时的操作 static struct file_operations my_fops = { 对文件操作结构体成员定义初始值 static int init my_init(void) { 创建设备节点 : result = register_chrdev_region(devno, 1, "sep4020_led"); 初始化硬件 sep4020_led_setup(); 注册设备, cdev_init(&(leddev->cdev), &sep4020_led_fops); TEL: FAX: 技术社区 : -72-

73 leddev->cdev.owner = THIS_MODULE; err = cdev_add(&leddev->cdev, devno, 1); static void exit my_exit(void) { 删除设备节点, 注销设备 4.2 Linux 内核模块 Linux 设备驱动会以内核模块的形式出现, 因此, 学会编写 Linux 内核模块编程是学习 Linux 设备驱动的先决条件 大家有没有想过 linux 设备这么多, 如果把每个设备驱动都编译进内核岂不是 linux 的内核越来越庞大了吗? 那有没有一种机制使得编译出的内核本身并不需要包含所有功能, 而在这些功能需要被使用的时候, 其对应的代码被动态地加载到内核中呢? 答案是肯定的,Linux 提供了这样的一种机制, 这种机制被称为模块 (Module) 模块具有这样的特点: 模块本身不被编译入内核映像, 这控制了内核的大小 模块一旦被加载, 它就和内核中的其它部分完全一样 为了建立读者对模块的初步感性认识, 我们先来看一个最简单的内核模块 Hello Module 编写 Hello Module 源代码 在此我们介绍一个运行于内核态的 Hello Module 程序, 它其实是一个最简单的驱动程序模块 我们将 Hello Module 的源代码放在 /root/code 目录, 文件名为 sep4020_hellomodule.c, 源代码内容如下 : #include <linux/kernel.h> #include <linux/module.h> MODULE_LICENSE("GPL"); static int init sep4020_hello_module_init(void) { printk("hello, sep4020 module is installed!\n"); return 0; TEL: FAX: 技术社区 : -73-

74 static void exit sep4020_hello_module_cleanup(void) { printk("good-bye, sep4020 module was removed!\n"); module_init(sep4020_hello_module_init); module_exit(sep4020_hello_module_cleanup); 这个最简单的内核模块只包含内核模块加载函数 卸载函数和对 GPL 许可权限的声明以及一些描述信息 编译它会产生 sep4020_hellomodule.ko 目标文件, 通过 insmod sep4020_hellomodule.ko 命令可以加载它, 通过 rmmod sep4020_hellomodule.ko 命令可以卸载它, 加载时输出 Hello, sep4020 module is installed!, 卸载时输出 Good-bye, sep4020 module was removed! 内核模块中用于输出的函数是内核空间的 printk() 而非用户空间的 printf(), printk() 的用法和 printf() 基本相似, 但前者可定义输出级别,printk() 可作为一种最基本的内核调试手段 编译 Hello Module 源代码 (1) 静态加载模块由于这个模块是加到嵌入式 linux 的内核中的, 所以它肯定会用到许多嵌入式 linux 源码的头文件的, 我们的嵌入式 linux 的内核源码位置在 /linux/ 下面, 这中间的链接过程非常复杂, 为了不让我们手动输入编译指令, 一般编译 2.6 版本的驱动模块需要把驱动代码加入内核代码树, 并做相应的配置, 如下步骤 ( 注意 : 实际上以下步骤均已经做好, 你只需要打开检查一下直接编译就可以了 ): Step1: 编辑配置文件 Kconfig, 加入驱动选项, 使之在 make menuconfig 的时候出现打开 /linux/drivers/char/sep4020_char//kconfig 文件, 添加如图 4.3 所示 : TEL: FAX: 技术社区 : -74-

75 图 4.3 保存退出, 这时在 /linux 目录位置运行一下 make menuconfig 就可以在 Device Drivers / Character devices 菜单中看到刚才所添加的选项了, 按下空格键将会选择为 <M>, 此意为要把该选项编译为模块方式 ; 再按下空格会变为 <*>, 意为要把该选项编译到内核中, 在此我们选择 <M>, 如图 4.4: [root@localhost linux]# make menuconfig 图 4.4 TEL: FAX: 技术社区 : -75-

76 Step2: 通过上一步, 我们虽然可以在配置内核的时候进行选择, 但实际上此时执行编译内核还是不能把 sep4020_hellomodule.c 编译进去的, 还需要在 Makefile 中把内核配置选项和真正的源代码联系起来, 打开 /linux/drivers/char/sep4020_char/makefile, 如图 4.5 添加并保存退出 : 图 4.5 Step3: 这时回到 linux 源代码根目录位置, 执行 make modules, 就可以生成我们所需要的内核模块文件 sep4020_hellomodule.ko 了 (2) 动态加载静态加载用户一旦把源文件放到内核源码中去后, 就几乎不用再管模块的配置问题了, 模块跟着内核编译就会出来模块文件了, 但这样也是比较麻烦因为我们并不想知道不同产品内核的不同结构, 我们只想知道怎样只编译这个模块而不用兴师动众每次都去编译内核, 这里我们就得用到自己动手写一个简单的 Makefile 文件, 通过这个 Makefile 就把模块相关配置问题都解决了 为此我们得在源码 sep4020_hellomodule.c 的所在位置 /root/code/ 下新建一个名为 Makefile 的文件, 其中的内容是 : KERNELDIR = /linux TEL: FAX: 技术社区 : -76-

77 PWD := $(shell pwd) ARCH = arm CROSS_COMPILE = arm-linux-gcc CC = $(CROSS_COMPILE) obj-m := sep4020_hellomodule.o modules: $(MAKE) -C $(KERNELDIR) M=$(PWD)// 此行前面是 TAB 键 LDDIN=$(PWD)/../include modules clean: rm -rf *.o *~ core.depend.*.cmd *.ko *.mod.c.tmp_versions// 此行前面是 TAB 键.PHONY: modules modules_install clean 注意 : 由于 makefile 特别 娇 贵, 建议不要复制, 若要复制, 则注意标注的两行必须以 TAB 键开头, 其它行顶行写, 所有的字母与符号必须在英文状态下输入, 否则会发生错误 你可以根据图 4.6 中命令的颜色来判断是否打对, 颜色不同的语句均是有问题的 图 4.6 将 Makefile 文件保存退出 ; 其中 KERNELDIR 是指定内核源码的根目录, TEL: FAX: 技术社区 : -77-

78 PWD 是指定源码文件和 Makefile 的目录所在,ARCH 是指定 cpu 的体系结构, CROSS_COMPILE 是指定编译器 Makefile 写好后, 我们就能进行模块的编译工作了 : 先进入 Makefile 的目录下 /root/code/; 然后输入 make modules, 这样在 /root/code/ 下面就能生成我们的模块文件 sep4020_hellomodule.ko 文件了, 所有操作如图 4.7 所示 : 图 4.7 至此, 我们已经完成了模块驱动的编译 我们在这里推荐大家使用第二种方法 把 HelloModule 下载到开发板并安装使用 最简单的方法莫过于把 sep4020_hellomodule.ko 拷贝到网络文件系统中, 这样你就可以直接在板子上运行程序了, 当然你也可以使用其他方法 假定我们已经把 sep4020_hellomodule.ko 放到了板子的 /demo/ 目录下, 现在执行 : #insmod sep4020_hellomodule.ko 可以看到该模块已经被装载了 ; 再执行, 可以看到该模块被卸载 : #rmmod sep4020_hellomodule.ko TEL: FAX: 技术社区 : -78-

79 整个过程如下图 4.7: 图 4.8 在此我们总结下 linux 内核模块的基本组成 : 模块加载函数 ( 一般需要 ); 当通过 insmod 或 modprobe 命令加载内核模块时, 模块的加载函数会自动被内核执行, 完成本模块的相关初始化工作 模块卸载函数 ( 一般需要 ); 当通过 rmmod 命令卸载某模块时, 模块的卸载函数会自动被内核执行, 完成与模块卸载函数相反的功能 模块许可证声明 ( 必须 ); 许可证 (LICENSE) 声明描述内核模块的许可权限, 如果不声明 LICENSE, 模块被加载时, 将收到内核被污染 (kernel tainted) 的警告 在 Linux 2.6 内核中, 可接受的 LICENSE 包括 GPL GPL v2 GPL and additional rights Dual BSD/GPL Dual MPL/GPL 和 Proprietary 大多数情况下, 内核模块应遵循 GPL 兼容许可权 Linux 2.6 内核模块最常见的是以 MODULE_LICENSE( "Dual BSD/GPL" ) 语句声明模块采用 BSD/GPL 双 LICENSE 模块参数 ( 可选 ); 模块参数是模块被加载的时候可以被传递给它的值, 它本身对应模块内部的全局变量 TEL: FAX: 技术社区 : -79-

80 模块导出符号 ( 可选 ); 内核模块可以导出符号 (symbol, 对应于函数或变量 ), 这样其它模块可以使用本模块中的变量或函数 模块作者等信息声明 ( 可选 ); 编写模块就按照上面这些结构进行填充就行了 4.3 Linux 字符驱动程序的设计 在 Linux2.6 内核中使用 cdev 结构来描述字符设备,cdev 结构体的一个定义如下 : struct cdev { struct kobject kobj; struct module *owner; const struct file_operations *ops; struct list_head list; dev_t dev; unsigned int count; ; 这其中 dev_t 成员定义了 32 位的设备号, 其中高 12 位为主设备号, 低 20 位为次设备号 而 cdev 结构体的另一个成员 file_operations 则定义了字符设备驱动程序提供给虚拟文件系统的接口函数 下面的函数可以用来操作 cdev 结构体 void cdev_init(struct cdev* dev, struct file_operations * fops); struct cdev* cdev_alloc(void); void cdev_put(struct cdev* p); int cdev_add(struct cdev*, dev_t, unsigned); void cdev_del(struct cdev*); 函数 cdev_alloc() 函数用于动态申请一个 cdev 内存 函数 cdev_init 用于初始化 cdev 的成员, 并建立 cdev 和 file_operations 之间的连接 而函数 cdev_add 和 cdev_del 分别向系统添加和删除一个 cdev 结构, 完成字符设备的注册和注销 当我们需要向系统添加字符设备的时候, 我们需要调用 cdev_add 函数来注册字符设备 而在此之前, 我们需要先调用 register_chrdev_region() 或 alloc_chrdev_region() 来向系统申请设备号 下面是这两个函数的定义 : TEL: FAX: 技术社区 : -80-

81 int register_chrdev_region(dev_t from, unsigned count, const char* name); int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char* name); void unregister_chrdev_region(dev_t from, unsigned count); 函数 register_chrdev_region 用于已知起始设备的设备号的情况, 而函数 alloc_chrdev_region 则用于设备号未知, 向系统动态申请未被占用的设备号的情况 函数调用成功后, 会自动在第一个参数中返回得到的设备号 同样, 在调用 cdev_del 函数从系统注销字符设备之后, 应该使用 unregister_chrdev_region 来释放原来申请的设备号 编写流水灯驱动程序源码 : 在 /linux/driver/char/sep4020_char/ 下面新建一个 sep4020_flowled.c 文件, 编写文件内容如下 : #include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/cdev.h> //#include <linux/interrupt.h> #include <linux/delay.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/io.h> #include <asm/hardware.h> #define KEY_MAJOR 256 /* 主设备号 */ #define LED_ON 1 #define LED_OFF 2 TEL: FAX: 技术社区 : -81-

82 unsigned int i=0; struct led_dev { struct cdev cdev; unsigned char value; ; struct led_dev *leddev; int sep4020_flowled_open(struct inode *inode, struct file *filp) { struct led_dev *dev ; filp->private_data = &leddev; // 将设备结构体指针赋值给文件私有数据指针 dev = filp->private_data; dev->value = 0; return 0; int sep4020_flowled_release(struct inode *inode, struct file *filp) { return 0; static ssize_t sep4020_flowled_read(struct file *filp, char user *buf, size_t size, loff_t *ppos) { //struct led_dev *pdev = flip->private_data; //if (copy_to_usr(buf, &(dev->value),1)) // { // return -EFAULT; TEL: FAX: 技术社区 : -82-

83 // return 0; static ssize_t sep4020_flowled_write(struct file *filp, const char user *buf, size_t size, loff_t *ppos) { return 0; int sep4020_flowled_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { struct led_dev *dev = filp->private_data; unsigned int j; switch (cmd) { case LED_ON: j=i%12; if(j<6) dev->value =1<<j; else dev->value >>=1; *(volatile unsigned long*)gpio_porte_data_v = dev->value; //flow led is open; //mdelay(500); i++; break; case LED_OFF: dev->value = 0; *(volatile unsigned long*)gpio_porte_data_v = 0; //flow led is close; TEL: FAX: 技术社区 : -83-

84 break; default: return -ENOTTY; return 0; static const struct file_operations sep4020_flowled_fops = {.owner = THIS_MODULE,.read = sep4020_flowled_read,.write = sep4020_flowled_write,.ioctl = sep4020_flowled_ioctl,.open = sep4020_flowled_open,.release = sep4020_flowled_release, ; static void sep4020_flowled_setup(void) { *(volatile unsigned long*)gpio_porte_sel_v = (0x1f); // 作为通用用途 *(volatile unsigned long*)gpio_porte_dir_v &= ~(0x1f );// 输出 *(volatile unsigned long*)gpio_porte_data_v &= ~(0x1f );// 初始输出拉低 static int init sep4020_flowled_init(void) { int err,result; dev_t devno = MKDEV(KEY_MAJOR, 0); TEL: FAX: 技术社区 : -84-

85 if(key_major) result = register_chrdev_region(devno, 1, "sep4020_flowled"); else { result = alloc_chrdev_region(&devno, 0, 1, "sep4020_flowled"); if(result < 0) return result; /* 动态申请设备结构体的内存 */ leddev = kmalloc(sizeof(struct led_dev),gfp_kernel); if (!leddev) { result = -ENOMEM; goto fail_malloc; memset(leddev,0,sizeof(struct led_dev)); /* 注册中断函数 */ /* 对键盘进行初始化 */ sep4020_flowled_setup(); cdev_init(&(leddev->cdev), &sep4020_flowled_fops); leddev->cdev.owner = THIS_MODULE; err = cdev_add(&leddev->cdev, devno, 1); if(err) printk("adding err\r\n"); return 0; fail_malloc: unregister_chrdev_region(devno,1); return result; TEL: FAX: 技术社区 : -85-

86 static void exit sep4020_flowled_exit(void) { cdev_del(&leddev->cdev); kfree(leddev); printk("sep4020_flowled_exit\n"); unregister_chrdev_region(mkdev(key_major, 0),1); module_init(sep4020_flowled_init); module_exit(sep4020_flowled_exit); MODULE_AUTHOR("fp"); MODULE_LICENSE("GPL"); 这个驱动的内容大家得仔细看一遍, 并和前面的驱动理论知识进行对比, 这 样你就会更好的理解 linux 驱动的结构和框架, 这个驱动所实现的功能是及其简 单的就是让 UB4020 MBT 板子上面的 5 个流水灯依次亮一遍 编译流水灯驱动源代码 由于这个模块是加到嵌入式 linux 的内核中的, 所以它肯定会用到许多嵌入 式 linux 源码的头文件的, 我们的嵌入式 linux 的内核源码位置在 /linux/ 下面, 这 中间的链接过程非常复杂, 为了不让我们手动输入编译指令, 一般编译 2.6 版本 的驱动模块需要把驱动代码加入内核代码树, 并做相应的配置, 如 : (1) 修改 /linux/driver/char/sep4020_char/kconfig 文件 ; 添加 : config SEP4020_FLOWLED tristate "sep4020 flowled" default y (2) 修改 /linux/driver/char/sep4020_char/makefile 文件 ; 添加这句话 : obj-$(config_sep4020_flowled) +=sep4020_flowled.o (3) 在 /linux/ 目录下运行 make menuconfig 并将 flowled 选项选成 module 形式进行编译 ; TEL: FAX: 技术社区 : -86-

87 图 4.9 (4) 在 /linux 下运行 make modules 生成 sep4020_flowled.ko 模块文件 下载流水灯模块到开发板上运行 (1) 将开发板上电, 并将 sep4020_flowled.ko 拷贝到网络文件系统 nfs/demo/ 目录下面 ; (2) 在 /dev/ 目录下创建一个设备节点 flowled; /dev # mknod flowled c (3) 在 /demo/ 目录下建立一个测试程序 led.c; #include <stdio.h> #define OPEN 1 #define CLOSE 2 int main(int argc, char **argv) { int fd; int i,j; fd = open("/dev/flowled",0); if(fd == -1) { printf("wrong\r\n"); exit(-1); for(j=0; j<41; j++) { TEL: FAX: 技术社区 : -87-

88 ioctl(fd, OPEN,0); for(i=0; i< ; i++); close(fd); return 0; (4) 编译测试程序 : [root@localhost demo]# arm-linux-gcc o led led.c [root@localhost demo]# ls button_arm hellomodule.ko helloworld_arm led led.c led.c~ sep4020_flowled.ko (5) 进入 /demo/ 下加载驱动模块如图 4.0 图 4.10 (6) 运行流水灯应用程序, 便出现了我们熟悉的流水灯界面图 4.11: 图 4.11 注 : 由于 EVB 1.5 的板子不支持流水灯, 流水灯实验只能在 MBT 的板子上运行 TEL: FAX: 技术社区 : -88-

89 第五章 SEP4020 的 HAL 层的应用 HAL 层的含义是硬件抽象层, 它是位于 Linux 操作系统内核 ( 包含驱动 ) 与硬件电路之间的接口层, 其目的在于将硬件抽象化 它隐藏了特定平台的硬件接口细节, 为操作系统提供虚拟硬件平台, 使其具有硬件无关性, 可在多种平台上进行移植 从软硬件测试的角度来看, 软硬件的测试工作都可分别基于硬件抽象层来完成, 使得软硬件测试工作的并行进行成为可能 5.1 硬件抽象层的介绍 我们之所以要提出这个 HAL 层是由于现在 SEP4020 的硬件平台类型很多像 EVB 系列,MBT 系列,MINI4020 系列,EPOS 系列, 这些不同类型的硬件如果想应用我们的 SEP4020 的 SDK, 那么我们就要为每套平台移植驱动, 因为它们的 I/O 硬件口线都不一样的, 所以我们经过讨论认为 HAL 层可能是解决这个问题的一个比较好的方法 HAL 层的框架 我们的 HAL 层是位于驱动层和硬件层的中间, 它本身是把 SEP4020 的硬件资源, 主要是 GPIO 口和中断抽象出来了, 驱动想用硬件资源就只能到 HAL 层去申请了, 所以在 HAL 层我们能够看到所有的硬件资源的使用情况, 下面我们看下 HAL 在整个 linux 中的位置 : Linux 内核 VFS 字符型驱动 块设备驱动和网络驱动 HAL( 包含 GPIO 和中断 ) SEP4020 硬件平台 TEL: FAX: 技术社区 : -89-

90 5.1.2 HAL 层的内容介绍 我们的 HAL 层由于主要包含两种资源 ( 中断和 GPIO), 所以我们必须在这里对这两种资源的使用作一个详细说明 GPIO 口使用 在这里我们将 GPIO 的使用分成两种类型 : 第一种是 GPIO 口单根线的使用, 也即 bit 的操作 ; 第二种是多个 bits 或整个 port 的使用, 这里我们提供了两组宏来操作两种不同类型, 驱动中间是不能直接使用单个和整个 port 的, 只能通过这些宏来操作 GPIO 的, 这样就将他们与具体的硬件分开了 #define REG32(addr) (*(volatile unsigned int *)(addr)) /* bit operation */ #define SET_BIT(port,bit) REG32(port) = (1 << bit) #define CLR_BIT(port,bit) REG32(port) &= (~(1 << bit)) #define GET_BIT(port,bit) (REG32(port) & (1 << bit)) // 对单个 bit 置位 // 对单个 bit 清零 // 获取单个 bit 的值 /* port or many bit operation */ #define SET_PORT_VALUE(port,value,mask) ({unsigned long res_port = REG32(port); REG32(port) = (res_port & (~mask)) (value & mask); ) // 对没有 mask 的 port 位赋值 value #define SET_PORT_MASK(port,mask) REG32(port) = mask // 对没有 mask 的 port 位置位 #define CLR_PORT_MASK(port,mask) REG32(port) &= (~mask) // 对没有 mask 的 port 位清零 #define GET_PORT_MASK(port,mask) (REG32(port) & mask) // 获取没有 mask 的 port 位的值 外部中断的使用 对于外部中断我们也是统一接管的, 驱动想使用也是需要在 HAL 层申请的, 这里涉及到两种操作 : 第一种 : 中断的申请和配置 ; 第二种 : 中断的清除 /* EXTERN INTERRUPT */ /* 中断类型定义 */ #define RISING_EDGE_TRIG 0x0 #define FALLING_EDGE_TRIG 0x1 #define HIGHT_LEVEL_TRIG 0x2 #define LOW_LEVEL_TRIG 0x3 /* 中断的申请和配置 */ TEL: FAX: 技术社区 : -90-

91 #define CONFIG_INT(int_num,int_type) \ do{ \ if(int_num == 11){ \ (*(volatile unsigned long*)gpio_portf_sel_v) = 0x0001 ;(*(volatile unsigned long*)gpio_portf_dir_v) = 0x0001 ; (*(volatile unsigned long*)gpio_portf_intrctl_v) = int_type;(*(volatile unsigned long*)gpio_portf_inctl_v) = 0x0001;(*(volatile unsigned long*)gpio_portf_intrclr_v) = 0x0001;(*(volatile unsigned long*)gpio_portf_intrclr_v) = 0x0000;\ else if(int_num < 11){ \ *(volatile unsigned long*)gpio_porta_sel_v = 0x1 << (int_num - 1);*(volatile unsigned long*)gpio_porta_dir_v = 0x1 << (int_num - 1);*(volatile unsigned long*)gpio_porta_intrctl_v = int_type << ((int_num - 1)*2);*(volatile unsigned long*)gpio_porta_inctl_v = 0x1 << (int_num - 1);*(volatile unsigned long*)gpio_porta_intrclr_v = 0x1 << (int_num - 1);*(volatile unsigned long*)gpio_porta_intrclr_v = 0x0000;\ while(0) /* 外 部 中 断 的 清 除 */ #define CLR_INT(int_num) \ do{ \ if(int_num == 11){ \ *(volatile unsigned long*)gpio_portf_intrclr_v = 0x0001;*(volatile unsigned long*)gpio_portf_intrclr_v = 0x0000; \ else if(int_num < 11){ \ *(volatile unsigned long*)gpio_porta_intrclr_v = 0x1 << (int_num - 1);*(volatile unsigned long*)gpio_porta_intrclr_v = 0x0000; \ while(0) 5.2 硬件抽象层的实际应用 经过上面的介绍, 大家应该对 HAL 层有所了解了, 现在我们开始以一个具体的实例来使用它 在这里我是以 5*5 键盘为例来说明如何添加键盘的 HAL 层及以后硬件改变时该怎样修改 HAL 层 键盘 HAL 层的建立 我们首先要知道键盘需要五根 GPIO 口和五个外部中断, 所以在这里两种资源的使用我们都需要申请, 在 sep4020_hal.h 中我们需要添加的内容如下 TEL: FAX: 技术社区 : -91-

92 /* * key board interface * */ /*---key interrupt define 键盘中断的申请 */ #define COL1_INT INTSRC_EXTINT0 #define COL2_INT INTSRC_EXTINT1 #define COL3_INT INTSRC_EXTINT2 #define COL4_INT INTSRC_EXTINT3 #define COL5_INT INTSRC_EXTINT4 #define COL_INT_TYPE LOW_LEVEL_TRIG // 定义键盘的中断触发类型是低电平触发 /* 键盘列 port 端口的申请 */ #define COL_MASK (0x1f) #define COL_SEL_PORT GPIO_PORTA_SEL_V #define COL_DIR_PORT GPIO_PORTA_DIR_V #define COL_DATA_PORT GPIO_PORTA_DATA_V /* 键盘列五个 bits 的申请 */ #define COL1_BIT 0 #define COL1_SEL_PORT GPIO_PORTA_SEL_V #define COL1_DIR_PORT GPIO_PORTA_DIR_V #define COL1_DATA_PORT GPIO_PORTA_DATA_V #define COL2_BIT 1 #define COL2_SEL_PORT GPIO_PORTA_SEL_V #define COL2_DIR_PORT GPIO_PORTA_DIR_V #define COL2_DATA_PORT GPIO_PORTA_DATA_V #define COL3_BIT 2 #define COL3_SEL_PORT GPIO_PORTA_SEL_V #define COL3_DIR_PORT GPIO_PORTA_DIR_V #define COL3_DATA_PORT GPIO_PORTA_DATA_V #define COL4_BIT 3 #define COL4_SEL_PORT GPIO_PORTA_SEL_V #define COL4_DIR_PORT GPIO_PORTA_DIR_V #define COL4_DATA_PORT GPIO_PORTA_DATA_V TEL: FAX: 技术社区 : -92-

93 #define COL5_BIT 4 #define COL5_SEL_PORT GPIO_PORTA_SEL_V #define COL5_DIR_PORT GPIO_PORTA_DIR_V #define COL5_DATA_PORT GPIO_PORTA_DATA_V /* 键盘行 port 的申请 */ #define ROW_MASK ( 0x1f) #define ROW_SEL_PORT GPIO_PORTD_SEL_V #define ROW_DIR_PORT GPIO_PORTD_DIR_V #define ROW_DATA_PORT GPIO_PORTD_DATA_V /* 键盘行五个 bits 的申请 */ #define ROW1_BIT 0 #define ROW1_SEL_PORT GPIO_PORTD_SEL_V #define ROW1_DIR_PORT GPIO_PORTD_DIR_V #define ROW1_DATA_PORT GPIO_PORTD_DATA_V #define ROW2_BIT 1 #define ROW2_SEL_PORT GPIO_PORTD_SEL_V #define ROW2_DIR_PORT GPIO_PORTD_DIR_V #define ROW2_DATA_PORT GPIO_PORTD_DATA_V #define ROW3_BIT 2 #define ROW3_SEL_PORT GPIO_PORTD_SEL_V #define ROW3_DIR_PORT GPIO_PORTD_DIR_V #define ROW3_DATA_PORT GPIO_PORTD_DATA_V #define ROW4_BIT 3 #define ROW4_SEL_PORT GPIO_PORTD_SEL_V #define ROW4_DIR_PORT GPIO_PORTD_DIR_V #define ROW4_DATA_PORT GPIO_PORTD_DATA_V #define ROW5_BIT 4 #define ROW5_SEL_PORT GPIO_PORTD_SEL_V #define ROW5_DIR_PORT GPIO_PORTD_DIR_V #define ROW5_DATA_PORT GPIO_PORTD_DATA_V 键盘驱动的更改 我们在 sep4020_hal.h 中定义了键盘相应的资源, 在驱动里我们就只能用 HAL 层的键盘资源, 而不能直接去操作 4020 的 IO 口寄存器了, 也就是说我们要把以前操作 GPIO 和中断的语句全部换成现在的 HAL 层的操作宏 这里面我仅举 TEL: FAX: 技术社区 : -93-

94 几个例子说明 : (1) 键盘硬件 setup 函数 static void sep4020_key_setup(void) { // 关闭键盘中断 maskkey(); SET_PORT_MASK(ROW_SEL_PORT,ROW_MASK); CLR_PORT_MASK(ROW_DATA_PORT,ROW_MASK); CLR_PORT_MASK(ROW_DIR_PORT,ROW_MASK); /* CONFIG_INT(COL1_INT,COL_INT_TYPE); CONFIG_INT(COL2_INT,COL_INT_TYPE); CONFIG_INT(COL3_INT,COL_INT_TYPE); CONFIG_INT(COL4_INT,COL_INT_TYPE); CONFIG_INT(COL5_INT,COL_INT_TYPE); *(volatile unsigned long*)gpio_portd_sel_v = 0x1F ; *(volatile unsigned long*)gpio_portd_dir_v &= (~0x1F); *(volatile unsigned long*)gpio_portd_data_v &= (~0x1F); //FP // 通用用途 // 输出 *(volatile unsigned long*)gpio_porta_sel_v = 0x001F ; // 通用用途 *(volatile unsigned long*)gpio_porta_dir_v = 0x001F ; // 输入 *(volatile unsigned long*)gpio_porta_intrctl_v = 0x03ff; // 低电平触发 *(volatile unsigned long*)gpio_porta_inctl_v = 0x001F; // 外部中断源输入 *(volatile unsigned long*)gpio_porta_intrclr_v = 0x001F; *(volatile unsigned long*)gpio_porta_intrclr_v = 0x0000; // 清除中断 */ // 开启键盘中断 unmaskkey(); 其中蓝色部分是我们以前对 GPIO 端口寄存器直接操作的, 现在全部换成前面黑色的语句来替换 (2) 在键盘中断函数中清中断 static irqreturn_t sep4020_key_irqhandler(int irq, void *dev_id, struct pt_regs *reg) { TEL: FAX: 技术社区 : -94-

95 // 关闭键盘中断 maskkey(); CLR_INT(irq); // 清除相应的外部中断 key_dev->keystatus = KEY_UNSURE; key_timer.expires = jiffies + KEY_TIMER_DELAY_JUDGE; add_timer(&key_timer); // 启动定时器 //we will turn on the irq in the timer_handler return IRQ_HANDLED; (3) 在行反转时的置位操作 static void write_row(int index, int HighLow) { switch (index) { case 0: if (HighLow) { //FP SET_BIT(ROW1_DATA_PORT,ROW1_BIT); else { CLR_BIT(ROW1_DATA_PORT,ROW1_BIT); break; case 1: if (HighLow) { SET_BIT(ROW2_DATA_PORT,ROW2_BIT); else { CLR_BIT(ROW2_DATA_PORT,ROW2_BIT); break; case 2: if (HighLow) { SET_BIT(ROW3_DATA_PORT,ROW3_BIT); TEL: FAX: 技术社区 : -95-

96 else { CLR_BIT(ROW3_DATA_PORT,ROW3_BIT); break; case 3: if (HighLow) { SET_BIT(ROW4_DATA_PORT,ROW4_BIT); else { CLR_BIT(ROW4_DATA_PORT,ROW4_BIT); break; case 4: if (HighLow) { SET_BIT(ROW5_DATA_PORT,ROW5_BIT); else { CLR_BIT(ROW5_DATA_PORT,ROW5_BIT); break; default: break; 可以看出这个中间没有对硬件寄存器的直接操作, 全部是通过 HAL 层的宏来操作的其他的实例就不一一讲述了, 大家现在可以根据自己的需要将驱动中涉及到这两种资源的操作全部替换下 HAL 层的移植 前面讲述了 HAL 层的建立了, 现在若硬件平台发生了改变现在就能很方便通过更改 HAL 层的相关硬件定义来完成整个驱动的移植了, 再也用不着把所有的驱动统统修改一遍了 比如键盘的口线现在改变了, 我们需要更改的东西只有 sep4020_hal.h 文件下面这么多内容 TEL: FAX: 技术社区 : -96-

97 /* * key board interface * */ /*---key interrupt define 键盘中断的申请 */ #define COL1_INT INTSRC_EXTINT0 #define COL2_INT INTSRC_EXTINT1 #define COL3_INT INTSRC_EXTINT2 #define COL4_INT INTSRC_EXTINT3 #define COL5_INT INTSRC_EXTINT4 #define COL_INT_TYPE LOW_LEVEL_TRIG // 定义键盘的中断触发类型是低电平触发 /* 键盘列 port 端口的申请 */ #define COL_MASK (0x1f) #define COL_SEL_PORT GPIO_PORTA_SEL_V #define COL_DIR_PORT GPIO_PORTA_DIR_V #define COL_DATA_PORT GPIO_PORTA_DATA_V /* 键盘列五个 bits 的申请 */ #define COL1_BIT 0 #define COL1_SEL_PORT GPIO_PORTA_SEL_V #define COL1_DIR_PORT GPIO_PORTA_DIR_V #define COL1_DATA_PORT GPIO_PORTA_DATA_V #define COL2_BIT 1 #define COL2_SEL_PORT GPIO_PORTA_SEL_V #define COL2_DIR_PORT GPIO_PORTA_DIR_V #define COL2_DATA_PORT GPIO_PORTA_DATA_V #define COL3_BIT 2 #define COL3_SEL_PORT GPIO_PORTA_SEL_V #define COL3_DIR_PORT GPIO_PORTA_DIR_V #define COL3_DATA_PORT GPIO_PORTA_DATA_V #define COL4_BIT 3 #define COL4_SEL_PORT GPIO_PORTA_SEL_V #define COL4_DIR_PORT GPIO_PORTA_DIR_V #define COL4_DATA_PORT GPIO_PORTA_DATA_V #define COL5_BIT 4 #define COL5_SEL_PORT GPIO_PORTA_SEL_V TEL: FAX: 技术社区 : -97-

98 #define COL5_DIR_PORT GPIO_PORTA_DIR_V #define COL5_DATA_PORT GPIO_PORTA_DATA_V /* 键盘行 port 的申请 */ #define ROW_MASK ( 0x1f) #define ROW_SEL_PORT GPIO_PORTD_SEL_V #define ROW_DIR_PORT GPIO_PORTD_DIR_V #define ROW_DATA_PORT GPIO_PORTD_DATA_V /* 键盘行五个 bits 的申请 */ #define ROW1_BIT 0 #define ROW1_SEL_PORT GPIO_PORTD_SEL_V #define ROW1_DIR_PORT GPIO_PORTD_DIR_V #define ROW1_DATA_PORT GPIO_PORTD_DATA_V #define ROW2_BIT 1 #define ROW2_SEL_PORT GPIO_PORTD_SEL_V #define ROW2_DIR_PORT GPIO_PORTD_DIR_V #define ROW2_DATA_PORT GPIO_PORTD_DATA_V #define ROW3_BIT 2 #define ROW3_SEL_PORT GPIO_PORTD_SEL_V #define ROW3_DIR_PORT GPIO_PORTD_DIR_V #define ROW3_DATA_PORT GPIO_PORTD_DATA_V #define ROW4_BIT 3 #define ROW4_SEL_PORT GPIO_PORTD_SEL_V #define ROW4_DIR_PORT GPIO_PORTD_DIR_V #define ROW4_DATA_PORT GPIO_PORTD_DATA_V #define ROW5_BIT 4 #define ROW5_SEL_PORT GPIO_PORTD_SEL_V #define ROW5_DIR_PORT GPIO_PORTD_DIR_V #define ROW5_DATA_PORT GPIO_PORTD_DATA_V 通过改变上面的内容我们就能将键盘移植到了新的平台上了 TEL: FAX: 技术社区 : -98-

99 第六章 SEP4020 Linux 驱动程序说明 6.1 SEP4020 Linux 操作系统硬件资源分配表 DMA 控制器 (6 通道 ) 通道 使用情况 备注 5 未使用 4 未使用 3 SEP4020 USB Device 2 SD 1 IIS-UDA NAND 外部中断 (Linux 系统中注册 10 个外部中断, 使用时需要向系统申请 ) 9 未使用 8 ADS 未使用 6 未使用 5 S1R72V17 4 5x5 键盘 E 3 5x5 键盘 D 2 5x5 键盘 C 1 5x5 键盘 B 0 5x5 键盘 A 硬件定时器 ( 共 10 个 ) 10 未使用 16 位 9 未使用 16 位 8 未使用 16 位 7 未使用 16 位 6 未使用 5 针式打印机 4 热敏打印机 / 针式打印机 不能同时使用 TEL: FAX: 技术社区 : -99-

100 3 热敏打印机 / 针式打印机不能同时使用 2 Linux 系统使用 1 Linux 系统使用 表 字符型驱动的设备号列表 驱动名称 主设备号 General gpio 240 beep 245 射频卡 *64 LCD 248 FSK 249 针式打印机 250 触摸屏 251 内置 PSAM 卡 252 LED 253 5*5 键盘 254 热敏打印机 255 磁条卡读卡器 257 GPRS&CDMA 246 TEL: FAX: 技术社区 :

101 HDLC 259 外扩 PSAM 卡 258 表 6.2 TEL: FAX: 技术社区 :

102 6.3 字符型设备驱动 *5 键盘驱动 硬件原理图 图 驱动源码位置 /linux/drivers/char/sep4020_char/sep4020_key.c 内核编译相关选项 Device Driver->Character devices->sep4020 char drivers->sep4020 char device->sep4020 key driver( 图 6.4- 图 6.7) TEL: FAX: 技术社区 :

103 图 6.4 图 6.5 TEL: FAX: 技术社区 :

104 图 6.6 图 6.7 TEL: FAX: 技术社区 :

105 应用程序接口与程序样例 : Sdk3.4 中 5*5 键盘驱动实现了键盘有按键按下时的读操作, 如果没有按键按下读操作还可以等待, 而且对同时按下两个键或者更多的键进行了处理 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(int argc, char **argv) { int fd; int j; int length = 0; int buf[16] = {0; fd = open("/dev/buttons",o_rdonly); if(fd == -1) { printf("wrong\r\n"); exit(-1); while(1) { read(fd, buf, 3); // 从驱动得到的键值保存在 buf 数组内,3 可变 length = *(int*)buf; // 实际读取键值的个数 for(j = 1;j < (length+1);j++) { printf("%d\n",buf[j]); close(fd); TEL: FAX: 技术社区 :

106 return 0; RTC 实时时钟驱动 硬件原理图 RTC 模块为芯片内部模块, 无具体硬件原理图 驱动源码位置 /linux/drivers/char/sep4020_char/sep4020_rtc.c 内核编译相关选项 Device Driver->Character devices->sep4020 char drivers->sep4020 char device->sep4020 rtc driver( 图 6.8- 图 6.11) 图 6.8 TEL: FAX: 技术社区 :

107 图 6.9 图 6.10 TEL: FAX: 技术社区 :

108 图 应用程序接口与程序样例 设置实时时钟 RTC 是系统时钟和开发板时钟的交互, 可使用下列命令对 rtc 模块进行操作 date s // 设置操作系统时间,2009 年 04 月 07 号,12 点 20 分, 这 个时间只是存在在当前操作系统下, 断电后将丢失 hwclock w // 将系统时钟同步更新到 bios hwclock s // 将 bios 时钟同步更新到操作系统 因此在使用实时时钟的具体操作应为如下 : 首先, 使用 date s 来设置当前时 间 ; 其次, 系统时间更新完毕后使用 hwclock w 将系统系统更新到 rtc 模块中 ; 最后, 在系统开机启动代码中加入 hwclock s 将 bios 时间同步更新到系统中 ( 注 意, 这一步 sdk 中提供的文件系统已替用户完成 ) RTC 的闰年机制 : RTC 驱动的闰年机制支持到 2023 年, 若在 2023 年以后用户需自己软件处理 应用程序接口与程序样例 : Linux 下获得系统时间的 C 语言的实现代码如下 : #include <stdio.h> #include <time.h> int main() { time_t now; // 实例化 time_t 结构 struct tm *timenow; // 实例化 tm 结构指针 TEL: FAX: 技术社区 :

109 time(&now); //time 函数读取现在的时间 ( 国际标准时间非北京时间 ), 然后传值给 now timenow = localtime(&now); //localtime 函数把从 time 取得的时间 now 换算成你电脑中的时间 ( 就是你设置的地区 ) printf("local time is %s\n",asctime(timenow)); // 上句中 asctime 函数把时间转换成字符, 通过 printf() 函数输出 return 0; 触摸屏驱动 硬件原理图 硬件原理图如下 ( 图 6.12): 图 6.12 TEL: FAX: 技术社区 :

110 驱动源码文件位置 /linux/drivers/char/sep4020_char/sep4020_tp.c 内核编译相关选项 Device Driver->Character devices->sep4020 char drivers->sep4020 char device->sep4020 touchpad driver ( 图 图 6.16) 图 6.13 TEL: FAX: 技术社区 :

111 图 6.14 图 6.15 TEL: FAX: 技术社区 :

112 图 应用程序接口与程序样例 触摸屏的应用主要还是和 gui 挂钩的, 在我们提供的 sdk3.4 中, 触摸屏与 minigui 的接口层已经做好, 用户只需按照通用方式编写 minigui 程序就能调用触摸屏驱动 这里仅仅举一个小例子, 讲解脱离 minigui 如何调用触摸屏驱动, 直接读取 ad 采样值的代码 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(int argc, char **argv) { int fd; int i = 0; short buff[3]={0;// 注意是 short 类型 fd = open("/dev/tp",o_rdonly); if(fd == -1) { printf("wrong\r\n"); exit(-1); TEL: FAX: 技术社区 :

113 for(i = 0; i < 1000; i++) { read(fd,buf,3);// 调用设备驱动得到数据存放在 buf 中,buf[0] 是 up/down 信息, //0 是 down,4 是 up //buf[1] 是 x 轴坐标,buf[2] 是 y 轴坐标 printf("the xpix is %d,the ypix is %d,the zpix is %d\n",buf[1],buf[2],buf[0]); close(fd); return 0; PSAM 卡驱动 内置 PSAM 卡驱动 硬件原理图 硬件原理图如下 ( 图 6.17) 图 6.17 TEL: FAX: 技术社区 :

114 驱动源码位置 /linux/drivers/char/sep4020_char/sep4020_psam.c 内核编译相关选项 Device Driver->Character devices->sep4020 char drivers->sep4020 char device->sep4020 psam card driver( 图 图 6.21) 图 6.18 TEL: FAX: 技术社区 :

115 图 6.19 图 6.20 TEL: FAX: 技术社区 :

116 图 应用程序接口与程序样例 SDK3.4 中的 PSAM 卡驱动实现了冷复位 发送随机数 发送选择主文件命令 MAC 加密等等 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define COLDRESET 0X11 #define RECEIVE_LEN 0X12 int main(int argc, char **argv) { int fd, j; int receive_len[1] ={0; char *receive_buf; // 选择文件命令 char send3[10]={0x00,0xa4,0x04,0x0,0x05,0x11,0x22,0x33,0x44,0x55; // 初始化密钥命令 char send5[5]={0x80,0x1a,0x08,0x01,0x00; // 发送第一个数据包命令 char send6[29]= {0X80,0XFA,0X07,0X00,0X18,0X00,0X00,0X00,0X00,0X00,0X00,0X00, TEL: FAX: 技术社区 :

117 0X00,0X01,0X02,0X03,0X04,0X05,0X06,0X07,0X08,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00; // 发送后续数据包命令 char send7[29]= {0X80,0XFA,0X03,0X00,0X18,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00, 0X88,0X88,0X88,0X88,0X88,0X88,0X88,0X88,0X80,0X00,0X00,0X00,0X00, 0X00,0X00,0X00; // 发送最后一个数据包命令 char send8[29]= {0X80,0XFA,0X01,0X00,0X18,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X11,0X12,0X13,0X14,0X15,0X16,0X17,0X18,0X80,0X00,0X00,0X00,0X00, 0X00,0X00,0X00; fd = open("/dev/psam",o_rdwr); if(fd == -1) { printf("wrong\r\n"); exit(-1); // 冷复位 ioctl(fd, COLDRESET); ioctl(fd, RECEIVE_LEN, receive_len); // 获取接受数据的长度 printf("%d\n",receive_len[0]); receive_buf = (char *)malloc(receive_len[0]); if(receive_buf == NULL) { printf("not Enough Memory!\n"); return 0; read(fd, receive_buf, receive_len[0]); // 从驱动中得到的数据保存到 receive_buf 中 for(j = 0;j < receive_len[0]; j++) TEL: FAX: 技术社区 :

118 { printf("0x%x ",receive_buf[j]); printf("\n"); free(receive_buf); // 选择文件 write(fd, send3,10); ioctl(fd, RECEIVE_LEN, receive_len); printf("%d\n",receive_len[0]); receive_buf = (char *)malloc(receive_len[0]); if(receive_buf == NULL) { printf("not Enough Memory!\n"); return 0; read(fd, receive_buf, receive_len[0]); for(j = 0;j < receive_len[0]; j++) { printf("0x%x ",receive_buf[j]); printf("\n"); free(receive_buf); // 初始化密钥 write(fd, send5,5); ioctl(fd, RECEIVE_LEN, receive_len); printf("%d\n",receive_len[0]); receive_buf = (char *)malloc(receive_len[0]); if(receive_buf == NULL) { printf("not Enough Memory!\n"); TEL: FAX: 技术社区 :

119 return 0; read(fd, receive_buf, receive_len[0]); for(j = 0;j < receive_len[0]; j++) { printf("0x%x ",receive_buf[j]); printf("\n"); free(receive_buf); // 发送第一个数据包 write(fd, send6,29); ioctl(fd, RECEIVE_LEN, receive_len); printf("%d\n",receive_len[0]); receive_buf = (char *)malloc(receive_len[0]); if(receive_buf == NULL) { printf("not Enough Memory!\n"); return 0; read(fd, receive_buf, receive_len[0]); for(j = 0;j < receive_len[0]; j++) { printf("0x%x ",receive_buf[j]); printf("\n"); free(receive_buf); // 发送后续数据包 write(fd, send7,29); ioctl(fd, RECEIVE_LEN, receive_len); TEL: FAX: 技术社区 :

120 printf("%d\n",receive_len[0]); receive_buf = (char *)malloc(receive_len[0]); if(receive_buf == NULL) { printf("not Enough Memory!\n"); return 0; read(fd, receive_buf, receive_len[0]); for(j = 0;j < receive_len[0]; j++) { printf("0x%x ",receive_buf[j]); printf("\n"); free(receive_buf); // 发送最后一个数据包 write(fd, send8,29); ioctl(fd, RECEIVE_LEN, receive_len); printf("%d\n",receive_len[0]); receive_buf = (char *)malloc(receive_len[0]); if(receive_buf == NULL) { printf("not Enough Memory!\n"); return 0; read(fd, receive_buf, receive_len[0]); for(j = 0;j < receive_len[0]; j++) { printf("0x%x ",receive_buf[j]); printf("\n"); TEL: FAX: 技术社区 :

121 free(receive_buf); close(fd); return 0; 外扩 PSAM 卡驱动 硬件原理图 图 6.22 图 6.23 TEL: FAX: 技术社区 :

122 驱动源码位置 /linux/drivers/char/sep4020_char/sep4020_exic_pos.c 内核编译相关选项 Device Driver->Character devices->sep4020 char drivers->sep4020 char device->sep4020 psam card driver(for sepcial board) 图 6.24 图 6.25 TEL: FAX: 技术社区 :

123 图 6.26 图 应用程序接口与程序样例 运行应用程序时, 请仔细读 /nfs/demo/ex-psa m-pos/readme.txt 使用前请确认 J301 的 1 2 管脚有跳线帽,J1101 有跳线帽, 同时 SW301 打到 ON 并使用 9V 或者 12V 电源 cd /demo/ex-psam-pos TEL: FAX: 技术社区 :

124 insmod sep4020_exic_pos.ko./armic 注意 : 测试外扩 PSAM 卡时, 需要将 U703A 芯片移除, 将 IC_R/W 和 IC_CTL_R/W (PE7) 直接短接 ( 参考硬件原理图 ) #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define COLDRESET 0X11 #define RECEIVE_LEN 0X12 int main(int argc, char **argv) { int fd; int i; char receive_buf[50]; char receive_len[1]; // 选择文件命令 char send3[10]={0x00,0xa4,0x04,0x0,0x05,0x11,0x22,0x33,0x44,0x55; // 初始化密钥命令 char send5[5]={0x80,0x1a,0x08,0x01,0x00; // 发送第一个数据包命令 char send6[29]= {0X80,0XFA,0X07,0X00,0X18,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0 1,0X02,0X03,0X04,0X05,0X06,0X07,0X08,0X80,0X00,0X00,0X00,0X00,0X00,0X 00,0X00; // 发送后续数据包命令 char send7[29]= {0X80,0XFA,0X03,0X00,0X18,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X8 8,0X88,0X88,0X88,0X88,0X88,0X88,0X88,0X80,0X00,0X00,0X00,0X00,0X00,0X 00,0X00; // 发送最后一个数据包命令 char send8[29]= {0X80,0XFA,0X01,0X00,0X18,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1 1,0X12,0X13,0X14,0X15,0X16,0X17,0X18,0X80,0X00,0X00,0X00,0X00,0X00,0X 00,0X00; printf("begin open!!\n"); fd = open("/dev/ic",o_rdwr); if( fd == -1) { TEL: FAX: 技术社区 :

125 printf("open error!\n") ; exit(-1); //coldreset ioctl(fd, COLDRESET); ioctl(fd, RECEIVE_LEN, receive_len); read(fd, receive_buf, receive_len[0]); printf("coldreset: "); for(i = 0;i < receive_len[0]; i++) { printf("0x%.2x ",receive_buf[i]); printf("\n"); //select write(fd, send3,10); ioctl(fd, RECEIVE_LEN, receive_len); read(fd, receive_buf, receive_len[0]); printf("select file: "); for(i = 0;i < receive_len[0]; i++) { printf("0x%.2x ",receive_buf[i]); printf("\n"); //initial des write(fd, send5,5); ioctl(fd, RECEIVE_LEN, receive_len); read(fd, receive_buf, receive_len[0]); printf("initial des: "); for(i = 0;i < receive_len[0]; i++) { printf("0x%.2x ",receive_buf[i]); printf("\n"); //3des write(fd, send6,29); write(fd, send7,29); write(fd, send8,29); TEL: FAX: 技术社区 :

126 ioctl(fd, RECEIVE_LEN, receive_len); read(fd, receive_buf, receive_len[0]); printf("3des: "); for(i = 0;i < receive_len[0]; i++) { printf("0x%.2x ",receive_buf[i]); printf("\n"); if(close(fd)){ printf("close error!\n"); return 0; LCD 驱动 硬件原理图 硬件原理图如下 ( 图 6.28): 图 6.28 TEL: FAX: 技术社区 :

127 驱动源码位置 /linux/driver/vedio/sep4020fb.c sepfb.c sepfb.h 内核编译相关选项 Device Driver->Graphics support->sep *480 LCD support-> SEP *240 LCD support ( 图 图 6.33) 注 : 根据不同分辨率选择, 只能选择一个, 不能同时选择 图 6.29 TEL: FAX: 技术社区 :

128 图 6.30 图 6.31 TEL: FAX: 技术社区 :

129 Device Driver->Graphics support->console display driver-support 图 6.32 Device Driver->Graphics support->logo configuration 图 应用程序接口 1) 将 LCD 作为启动控制终端, 将内核启动信息输出在屏幕上, 需要修改 Linux 启动命令参数, 添加代码 console=tty0 ; 2) 操作 /dev/tty0 设备在 LCD 上显示字符, 指令为 echo helloworld > /dev/tty0 ; 3) 操作 /dev/fb0 设备在 LCD 上显示图片, 将图片转换为和屏幕参数相对应的 bin 文件, 通过指令 cp x.bin /dev/fb0 可将其显示显示在屏幕上 TEL: FAX: 技术社区 :

130 6.3.6 IIS 音频驱动 硬件原理图 硬件原理图如下 ( 图 6.34) 图 驱动源码位置 /linux/sound/oss/sep4020-uda1341.c 内核编译相关选项 Device Drivers->Sound->Open Sound System(DEPRECATED)( 图 图 6.38) TEL: FAX: 技术社区 :

131 图 6.35 图 6.36 TEL: FAX: 技术社区 :

132 图 6.37 图 应用程序接口 在 Linux 操作系统中, 所有的设备都被统一成文件, 通过对文件的访问方式 ( 首先 open, 然后 read/write, 同时可以使用 ioctl 读取 / 设置参数, 最后 close) 来访问设备 在 IIS 音频驱动中, 主要有以下的几种设备文件 : /dev/mixer: 访问声卡中内置的 mixer, 调整音量大小, 选择音源 /dev/dsp: 读这个设备就相当于录音, 写这个设备就相当于放音 例 : 播放 wav 应用程序样例说明 : 1) 音频设备只能以 O_WRONLY 或者 O_RDONLY 方式打开, 不能使用 O_RDWR 方式打开, 因为不支持同时录音和放音 2) 使用方法举例 "./oss /tmp/test.wav 22050", 会自动录音 2MB, 再将其播放出来 3) 支持调整音频采样率 : 支持 和 8000 四种采样率 #include <sys/ioctl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/soundcard.h> #define BUF_SIZE 4096 TEL: FAX: 技术社区 :

133 #define DEVICE_NAME "/dev/dsp" int audio_fd; // 声卡 FILE *file_fd; // 文件 int file_len; // 文件长度 const char *file_name = "test.wav"; unsigned char audio_buffer[buf_size]; unsigned char *file_name_creat; unsigned int audio_rate; void delay(long x) { unsigned long i; for(i=0; i<x; i++); int main(int argc, char *argv[]) { printf("this is an I2S record & play program.\n"); printf("please add a file name and the audio rate! such as \"./oss test.wav 44100\" \n\n\n"); delay(100000); file_name_creat = argv[1]; sscanf(argv[2],"%d", &audio_rate); printf("the file name is %s audio rate is %d \n",file_name_creat,audio_rate); delay(100000); /* 打开音频设备, 准备录音 */ if ((audio_fd = open(device_name, O_RDONLY)) == -1) { printf("open error\n"); return -1; /* 设置采样速率 */ int speed = audio_rate; if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed)==-1) { /* Fatal error */ TEL: FAX: 技术社区 :

134 printf("sndctl_dsp_speed error\n"); return -1; printf("the wav speed is %d\n",speed); /**/ int i=0; unsigned long loops_record = 500; //500*4KB=2MB file_fd = fopen(file_name_creat, "w"); printf("recording...\n"); for(i=0;i<loops_record;i++) { read(audio_fd,audio_buffer,4096); fwrite(audio_buffer, 4096, 1, file_fd); printf("recording...over\n"); /* 关闭设备和文件 */ fclose(file_fd); close(audio_fd); delay(100000); /* 打开音频设备, 准备录音 */ if ((audio_fd = open(device_name, O_WRONLY)) == -1) { printf("open error\n"); return -1; /* 设置采样格式 */ int format; format = AFMT_S16_LE; if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format) == -1) { /* fatal error */ printf("sndctl_dsp_setfmt error\n"); return -1; if (format!= AFMT_S16_LE) { /* 本设备不支持选择的采样格式. */ printf("sep4020 oss driver does not support AFMT_S16_LE"); TEL: FAX: 技术社区 :

135 /* 设置通道数 */ int channels = 2; /* 1=mono, 2=stereo */ if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) { /* Fatal error */ printf("sndctl_dsp_channels error"); return -1; if (channels!= 2) { /* 本设备不支持立体声模式... */ printf("sep4020 oss driver does "); /* 设置采样速率 */ speed = audio_rate; if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed)==-1) { /* Fatal error */ printf("sndctl_dsp_speed error\n"); return -1; printf("the wav speed is %d\n",speed); /* 打开并计算文件长度 */ file_fd = fopen(file_name_creat, "r"); fseek(file_fd,0,seek_end); // 定位到文件末 file_len = ftell(file_fd); // 文件长度 int loops = file_len/4096; /* 重新定位到文件头 */ fclose(file_fd); file_fd = fopen(file_name_creat, "r"); /* 播放 wav 文件 */ for(i=0;i<loops;i++) { fread(audio_buffer, 4096, 1, file_fd); TEL: FAX: 技术社区 :

136 write(audio_fd,audio_buffer,4096); /* 关闭设备和文件 */ fclose(file_fd); close(audio_fd); return 0; //DESCRIPTION("sep4020 uda1341 sound card test program"); 串口驱动 硬件原理图 硬件原理图如下 ( 图 6.39): 图 驱动源码位置 /linux/driver/serial/8250.c TEL: FAX: 技术社区 :

137 内核编译相关选项 Device Drivers->Character devices->serial drivers->8250/16550 and compatible serial support; Console on 8250/16550 and compatible serial port ( 图 图 6.43) 图 6.40 图 6.41 TEL: FAX: 技术社区 :

138 图 6.42 图 应用程序接口与程序样例 串口采用标准串口设计, 具体设计可参考第六章 GPRS/CDMA 程序开发简 介 ( 当中主要是对串口的操作 ), 关于串口更加深入的使用和研究可参考相关书 籍 热敏打印机驱动 : 硬件原理图 : 硬件原理图如下 ( 图 ) TEL: FAX: 技术社区 :

139 图 6.44 图 6.45 TEL: FAX: 技术社区 :

140 图 6.46 图 6.47 TEL: FAX: 技术社区 :

141 图 驱动源码位置 : /linux/drivers/char/sep4020_char/thermal_printer.c /linux/drivers/char/sep4020_char/thermal_printer.h 内核编译相关选项 : Device Driver->Character devices->sep4020 char drivers-> sep4020 char device-> sep4020 Thermal printer driver (for special board!) TEL: FAX: 技术社区 :

142 图 6.49 图 6.50 TEL: FAX: 技术社区 :

143 图 6.51 图 应用程序接口与程序样例 : (1) 热敏打印机在应用层具有中英文字模转换库, 这个转换库被做成了动态链接库 libfontchange.so, 这个库封装了将中英文字符串转换为字模的功能, 下面这个 TEL: FAX: 技术社区 :

144 实例将具体用到 (2) 在编译具体实例时, 编译方法是将 libfontchange.so 拷贝到源码程序的目录下, 如果源码文件是 printer_test.c 则命令是 : $ arm-linux-gcc -o printer_test.test printer_test.c libfontchange.so asc12x24.c #include <stdio.h> #include <sys/ioctl.h> #include <string.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> int main(int argc, char **argv) { extern unsigned char *asc12x24[]; //ASCII extern unsigned char *font24x24[]; //chinese int fd; int cur_h=0,cur_l=0; int num=0; unsigned char string[960][48]; //(384/8=48)*(24*40=960) unsigned char ch[1280],tmp; //(32*40=1280) unsigned char *filename; // 文件名 unsigned int i,j; // 循环变量 FILE *fp; // 文件指针 // 判断打印命令是否有错 if(argc == 2 && argv[1] ) { filename = (unsigned char*)malloc((unsigned int )strlen(argv[1])); memcpy(filename,argv[1],strlen(argv[1])); else { fprintf(stderr, "Usage: error \n"); exit(1); printf("please waiting!\n"); // 打开打印机设备 fd = open("/dev/printer",o_rdwr); if(fd == -1) { printf("open printer wrong!\r\n"); exit(-1); TEL: FAX: 技术社区 :

145 // 打开待打印的文件 printf("file name is: %s.\n",filename); fp=fopen(filename, "r"); if(fp == NULL) { printf("cannot open file!\n"); exit(1); memset(string,0x00,46080); // 读取文件中的字节 while(!feof(fp)) { ch[num]=fgetc(fp); printf("%x\t",ch[num]); num++; //ASCII=> 字模 ; 汉字 => 字模 for(i=0;i<num-2;i++) { if(cur_l >= 46 && ch[i+1]>0xa0) { cur_h++; cur_l=0; continue; if(ch[i]<0xa0) //ASCII { for(j=0;j<24;j++) { string[cur_h*24+j][cur_l+0] = *(asc12x24[ch[i]-0x20]+j*2+0); string[cur_h*24+j][cur_l+1] = *(asc12x24[ch[i]-0x20]+j*2+1); cur_l=cur_l+2; else //chinese { for(j=0;j<24;j++) { string[cur_h*24+j][cur_l+0] = *(font24x24[256*(ch[i+1]-0xa1)+ch[i]-0xa1]+j*3+0); string[cur_h*24+j][cur_l+1] = *(font24x24[256*(ch[i+1]-0xa1)+ch[i]-0xa1]+j*3+1); TEL: FAX: 技术社区 :

146 string[cur_h*24+j][cur_l+2] = *(font24x24[256*(ch[i+1]-0xa1)+ch[i]-0xa1]+j*3+2); cur_l=cur_l+3; i++; if(cur_l >=48) { cur_h=cur_h+1; cur_l=0; write(fd,string,(cur_h+1)*1152); fclose(fp); free(filename); printf("print Finished!\n"); close(fd); return 0; (3) 在 UB4020_POS_EDU 版上, 测试热敏打印机时, 把 J901 跳线接口处于 on 状态 在开发板正常启动后, 我们进入 /demo/ thermal_printer-demo(epos)/ 目录下里面提供了相应的代码, 还有已经编译好的测试程序 printer_test.test 其中里面得 test.txt 为要打印的内容 #insmod thermal_printer.ko #./printer_test.test test.txt 然后热敏电机就开始走纸, 打印 test.txt 里面得内容注 : 接口采用逻辑电路将 CPU 出来的 GPIO 和中断信号与打印头的控制信号进行有效隔离, 防止互相干扰, 其中的 J901 处于 on 状态时, 控制使能 ;J901 处于 OFF 状态时, 控制禁止 ; 此部分的控制信号与针式打印部分复用, 在同一时间只能将其中的一中使能, 不能同时使用 TEL: FAX: 技术社区 :

147 6.3.9 针式打印机驱动 : 硬件原理图 : 硬件原理图如下 图 6.53 图 6.54 TEL: FAX: 技术社区 :

148 图 6.55 图 6.56 TEL: FAX: 技术社区 :

149 图 驱动源码位置 : /linux/drivers/char/sep4020_char/sep4020_printer.c /linux/drivers/char/sep4020_char/sep4020_printer.h 内核编译相关选项 : Device Driver->Character devices->sep4020 char drivers->sep4020 char device->sep4020 Dot-Matrix Printer driver (for special board!) TEL: FAX: 技术社区 :

150 图 6.58 图 6.59 TEL: FAX: 技术社区 :

151 图 6.60 图 应用程序接口与程序样例 : 本驱动针对 BIXOLON 公司的 SMP150 型号的针式打印机开发的, 其它打印机可能不适用 由于针式打印机的托架电机在长时间供电的情况可有可能被烧坏, 所以在电源部分的 D1003 发光极管长时间亮的情况下最好断开电源 /#insmod sep4020_printer.ko /#mknod /dev/printer c TEL: FAX: 技术社区 :

152 /#./print_test TEST OK! 磁条卡读卡器驱动 硬件原理图 硬件原理图如下 图 驱动源码位置 /linux/drivers/char/sep4020_char/sep4020_mgcard.c 内核编译相关选项 Device Drivers Character devices sep4020 char drivers sep4020 char device sep4020_mgcd driver(for special board!) TEL: FAX: 技术社区 :

153 图 6.63 图 6.64 TEL: FAX: 技术社区 :

154 图 6.65 图 应用程序接口 启动前先检查 u-boot, 文件系统的烧写及相应跳线帽等启动设置 应用程序主要分为打开 (open), 读 (read) 和关闭 (close) 三个阶段 启动时显示 TEL: FAX: 技术社区 :

155 open the mgcard befor setup request irqs in request irqs mid request irqs out read begin 刷卡后能读出卡号数据 ; ? 例 : 刷卡应用程序 ( 只读二轨 ) int main(int argc, char **argv) { int fd; int num=0; // char a[50]={0; char a[150]={0; int i,j,k; fd = open("/dev/mg_card",o_rdonly); if(fd == -1) { printf("wrong\r\n"); exit(-1); // num = read(fd,a,50); // printf("num is %d\n",num); // for(k=0;k<50; k++) // printf("%c",a[k]); // printf("\a\n"); num = read(fd,a,150); printf("num is %d\n",num); for(k=0;k<150; k++) printf("%c",a[k]); // printf("card_num3:\n"); // for(k=num;k<150; k++) // printf("%c",a[k]); close(fd); return 0; TEL: FAX: 技术社区 :

156 射频卡驱动 硬件原理图 : 图 驱动源码位置 : /Linux/driver/char/sep4020_char/sep4020_rc531.c 和 /linux/driver//char/sep4020_char/mifare 内核编译相关选项 : Device Drivers->Character devices->sep4020 char devices->sep4020 RC531 driver TEL: FAX: 技术社区 :

157 图 6.68 图 6.69 TEL: FAX: 技术社区 :

158 图 6.70 图 应用程序接口与程序样例 必须有一张未加密的射频卡片, 最好是空卡, 还有带有 RC531 芯片的射频卡读卡装置! 在系统上电,LINUX 启动后加载 sep4020_rc531.ko 这个模块 ( 也可以选择加载进内核 ) 然后运行 mifare_demo 选择 b 读卡片内容此时出现要求选择输入一个 0 到 62 之间的数, 选择 0( 卡片的第 0 块放的是出厂资料, 其中前四个字节便是卡片的卡号 ): TEL: FAX: 技术社区 :

159 此时可以输入任何键以便继续 注意 : 卡片的第 0 块是放的出厂信息, 是不可以被写入的! TEL: FAX: 技术社区 :

160 6.4 SEP4020 Linux 块设备驱动 NAND FLASH 驱动 硬件原理图 硬件原理图如下 : 图 驱动源码位置 /linux/drivers/mtd/nand/sep4020.c TEL: FAX: 技术社区 :

161 内核编译相关选项 Device Drivers->Memory Technology Device->Nand Flash Device Drivers->Nand Device Support 图 6.73 图 6.74 TEL: FAX: 技术社区 :

162 图 6.75 图 应用程序接口与程序样例 SEP4020 使用的 Linux 系统在内核中将 NandFlash 分为四个区, 如下 : mtdblock0: 0x x M mtdblock1: 0x x M TEL: FAX: 技术社区 :

163 mtdblock2: 0x x1E M mtdblock3: 0x01E x M 对 nandflash 的操作一般是通过文件系统的方式进行的, 比如用户使用的文件系统就是在开发板的 nandflash 芯片上, 那用户基于此进行的所有读写都是对 nandflash 的操作, 这里以用户使用网络文件系统为例, 介绍如何使用 nandflash 芯片 打开串口终端, 在终端中输入 :mount t yaffs /dev/mtdblock2 /tmp, 这样就把我们的 nandflash 的第二个分区以 yaffs 的格式挂载到 /tmp 文件夹下, 之后对 /tmp 文件夹的所有操作都是对 nandflash 进行的 SD 卡驱动 硬件原理图 硬件原理图如下 : 图 驱动源码位置 /linux/drivers/mmc/sep_mci.c 和 /linux/drivers/mmc/sep_mci.h TEL: FAX: 技术社区 :

164 内核编译相关选项 Device Drivers->MMC/SD Card support->mmc support 图 6.78 图 6.79 TEL: FAX: 技术社区 :

165 图 6.80 把图中相应的三个选项选上, 这样就能把 SD 卡驱动编译进内核 应用程序接口与程序样例 在现在的开发板上是不支持 SD 卡热拔插的, 所以要让系统识别 SD 卡必须在开发板上电前将 SD 卡插入 SD 卡插座, 并且注意目前 SD 卡的驱动还不支持 2G 及 2G 以上的大容量 SD 卡, 上电时如果发现有一下启动信息就说明 SD 已经被系统识别出来了 命令 从这些启动信息可看出 SD 卡容量 1GB 大小, 接着进入 /dev 目录并键入 ls TEL: FAX: 技术社区 :

166 这样就说明系统识别出 SD 卡有两个分区 mmcblk0 和 mmcblk0p1, 但在这里只有 mmcblk0p1 能够使用, 为此我们得输入以下命令来挂载 SD 卡 : 了 Mount t vfat o sync /dev/mmcblk0p1 /mnt 这样就能将 SD 卡挂进系统了, 我们可以进入 /mnt 就能看到 SD 卡内的文件 USB device 驱动 硬件原理图 图 6.81 TEL: FAX: 技术社区 :

167 驱动源码位置 /linux/drivers/usb/gadget/ sep4020_udc.c /linux/drivers/usb/gadget/ sep4020_udc.h 内核编译相关选项 Device drives->usb support ->Usb Gadget Support ->File-backed storage Gadget 图 6.82 图 6.83 TEL: FAX: 技术社区 :

168 图 6.84 了 图 6.85 把如图中的 * 和 M 相应的都选上就能将 4020 本身的 usb device 编译进内核 应用程序接口与程序样例 4020 的 usb device 作用是让 4020 作为一个从设备连到电脑上, 这样 4020 可以把自己虚拟成一个 u 盘, 用户可以在电脑上直接对 4020 到相关资源进行操 TEL: FAX: 技术社区 :

169 作, 比如 SD 卡,SDRAM,NAND 等块设备资源, 这样远程读写 4020 到资源就 很简单了 在这里我们的 4020 只支持虚拟 u 盘, 不支持虚拟网卡等设备 使用 虚拟 u 盘的方法见用户手册 在这里我们将内存的 ram0 区的 195M 空间虚拟成 u 盘为例来说明下 usb device 的使用 在系统上电,linux 启动后, 我们得先加载 g_file_storage.ko 这个块模块 insmod g_file_storage.ko file=/dev/ram0 stall=0 removable=1 g_file_storage gadget: File-backed Storage Gadget, version: 28 November 2005 g_file_storage gadget: Number of LUNs=1 g_file_storage gadget-lun0: ro=0, file: /dev/ram0 其中 : ram0: 表示把 ram0 挂载为 U 盘 它还可以用 mtdblock2 和 mmcblk0 来代替, 它们的含意分别为 : 把 Nand Flash 的第三个分区 mtdblock2 挂载为 U 盘 把 mmc 卡的第一个分区 mmcblk0 挂载为 U 盘 removable=1: 表示可移动的介质 等这个模块加载好后就可以用 usb 线将 4020 连接到电脑上了, 当把 4020 连 到电脑上会报以下信息 : 输入上面命令后, 出现如下信息 : Go into INTRESET! Go into INTRESET! 0.06 USB: EP0OUTSTAT 2,transtat is 0x b 0.07 USB: brequesttype = 128 brequest = 6 wlength = USB: going into ep0 equeue! 0.09 USB: EP0OUTSTAT a,transtat is 0x USB: EP0_IN_DATA_PHASE... what now? Go into INTRESET! 0.11 USB: EP0OUTSTAT 2,transtat is 0x USB: brequesttype = 255 brequest = 255 wlength = USB: Operation not supported 0.14 USB: EP0OUTSTAT 2,transtat is 0x b 0.15 USB: brequesttype = 255 brequest = 255 wlength = USB: Operation not supported 0.17 USB: EP0OUTSTAT 2,transtat is 0x b 0.18 USB: brequesttype = 128 brequest = 6 wlength = 18 TEL: FAX: 技术社区 :

170 0.19 USB: going into ep0 equeue! 0.20 USB: EP0OUTSTAT a,transtat is 0x USB: EP0_IN_DATA_PHASE... what now? 0.22 USB: EP0OUTSTAT a,transtat is 0x b 0.23 USB: EP0_IN_DATA_PHASE... what now? 0.24 USB: EP0OUTSTAT a,transtat is 0x USB: EP0_IN_DATA_PHASE... what now? 中间略 IRQ LOCK: IRQ15 is locking the system, disabled USB: ep1-bulk not enabled USB: ep2-bulk not enabled 4020endpoint enable0.297 USB: enable ep1-bulk(1) ep81in-blk max endpoint enable0.298 USB: enable ep2-bulk(2) ep2out-blk max 40 g_file_storage gadget: full speed config # USB: going into ep0 equeue! ENTER ep2 wait for USBD_RECEIVETYPE_V 这时在上位机电脑的根目录下我们就能见到多了一个 可移动磁盘 (H:), 这 样就说明已经成功将 4020 虚拟成 u 盘了 注意 : 这里指的 device 是指集成在 SEP4020 微处理器上的 usb device 控制 器, 区别于 evb1.5 以上的开发板添加的 epson 的 72v17usb 芯片 S1R72V17 USB device 驱动 Epson 72v17 的 USB device 驱动, 不同于之前的 sep4020 usb device 硬件原理图 硬件原理图如下 TEL: FAX: 技术社区 :

171 图 6.86 图 驱动源码位置 /linux/drivers/usb/gadget/ sep4020_udc.c /linux/drivers/usb/gadget/ sep4020_udc.h 内核编译相关选项 Device Drivers->USB support->file-backed Storage Gadget testing version TEL: FAX: 技术社区 :

172 图 6.88 图 6.89 TEL: FAX: 技术社区 :

173 图 6.90 图 6.91 把如图中的 * 和 M 相应的都选上就能将 epson 72v17 本身的 usb device 编译 进内核了 应用程序接口与程序样例 Epson 72v17 usb device 的使用和 sep4020 usb device 的使用相同 Epson TEL: FAX: 技术社区 :

174 72v17 的 usb device 作用是让 sep4020 作为一个从设备连到电脑上, 这样 sep4020 可以把自己虚拟成一个 u 盘, 用户可以在电脑上直接对 sep4020 到相关资源进行操作, 比如 SD 卡,SDRAM,NAND 等块设备资源, 这样远程读写 sep4020 到资源就很简单了 Epson 72v17 不仅支持虚拟 u 盘, 还支持虚拟网卡等设备 使用虚拟 u 盘的方法见用户手册 在这里我们将内存的 ram0 区的 195M 空间虚拟成 u 盘为例来说明下 usb device 的使用 在系统上电,linux 启动后, 我们得先加载 g_file_storage.ko 这个块模块 insmod g_file_storage.ko file=/dev/ram0 stall=0 removable=1 可以看到如下信息 : g_file_storage gadget: File-backed Storage Gadget, version: 28 November 2005 g_file_storage gadget: Number of LUNs=1 g_file_storage gadget-lun0: ro=0, file: /dev/ram0 其中 : ram0: 表示把 ram0 挂载为 U 盘 它还可以用 mtdblock2 和 mmcblk0 来代替, 它们的含意分别为 : 把 Nand Flash 的第三个分区 mtdblock2 挂载为 U 盘 把 mmc 卡的第一个分区 mmcblk0 挂载为 U 盘 removable=1: 表示可移动的介质 这时在上位机电脑的根目录下我们就能见到多了一个 可移动磁盘 (H:), 这样就说明已经成功利用 Epson 72v17 将 sep4020 的 ram 空间虚拟成 u 盘了 S1R72V17 USB-HOST 驱动 硬件原理图 硬件原理图如下 TEL: FAX: 技术社区 :

175 图 驱动源码位置 /driver/usb/host/sir72xxx 内核编译相关选项 Device Drivers--->USB Support--->S1R72V17 HCD Support TEL: FAX: 技术社区 :

176 图 6.93 图 6.94 TEL: FAX: 技术社区 :

177 图 6.95 TEL: FAX: 技术社区 :

178 USB-HOST 使用方法 插上 U 盘, 出现如下信息 : usb 1-1: Product: iron man4g usb 1-1: Manufacturer: kyon usb 1-1: SerialNumber: usb 1-1: configuration #1 chosen from 1 choice ub(1.2): GetMaxLUN returned 1, using 2 LUNs /dev/uba1 1) 执行 mdev s, 在 dev 目录下可以自动生成 u 盘节点文件 uba1 2) 执行 mount /dev/uba1 /mnt 将 U 盘挂载到 mnt 目录 3) 进入 mnt 目录 : /dev # cd /mnt /mnt # ls c 语言 ~1.pdf i.mp3 mplayer2 qtopia~1.txt /mnt # cd.. 4) 不用时, 卸载 u 盘 / # umount /mnt / # usb 1-1: USB disconnect, address 4 TEL: FAX: 技术社区 :

179 6.4.6 NOR flash 驱动 硬件原理图 图 驱动源码位置 /Linux/drivers/mtd/maps/sep4020_norflash.c 内核编译相关选项 在 Makefile 中添加 : obj-$(config_mtd_sep4020_norflash) += sep4020_norflash.o 在 Kconfig 中添加 :config MTD_SEP4020_NORFLASH tristate "Map driver for NOR Flash on sep4020 board" depends on ARCH_SEP4020 && MTD 进入 make menuconfig: (1) Device Drivers Memory Technology Devices(MTD) RAM/ROM/Flash chip drivers Detect non-cfi AMD/JEDEC-compatible flash chips, Support for AMD/Fujitsu flash chips TEL: FAX: 技术社区 :

180 (2) Device Drivers Memory Technology Devices(MTD) Mapping drivers for chip access Map driver for NOR Flash on sep4020 board (3) File systems Miscellaneous filesystems Journaling Flash File System v2 (JFFS2) support, Compressed ROM file system support(cramfs) 图 6.97 图 6.98 TEL: FAX: 技术社区 :

181 图 6.99 图 TEL: FAX: 技术社区 :

182 图 图 TEL: FAX: 技术社区 :

183 图 图 TEL: FAX: 技术社区 :

184 图 挂载分区演示 1. 创建一个挂载目录并修改权限 /#mkdir /mnt/jffs2 /#chmod 777 /mnt/jffs2 2. 查看 mtd 层分区 /#cat /proc/mtd dev:size erasesize name mtd0: NOR FLASH on SEP4020 mtd1: BootLoader(256KB) mtd2:001c Kernel(1.75MB) mtd3: U-Boot mtd4: linux kernel mtd5: root mtd6: user 3. 挂载 NOR Flash 第二分区到指定目录 /#mount t jffs2 /dev/mtdblock2 /mnt/jffs2 /#cd /mnt/jffs2 /mnt/jffs2# ls jfs2 4. 查看挂载的文件系统 TEL: FAX: 技术社区 :

185 /mnt/jffs2 #cd /#df h Filesystem Size Used Available Use% Mounted on Rootfs 14,9G 4.8G 9.3G 34%/ /dev/rootfs 4,9G 4.8G 9.3G 34%/ /dev/mtdblock2 1.8M 100.0k 1.7M 6%/mnt/jffs2 5. 向分区中写入一个文件 /#cp /etc/profile /mnt/jffs2 /#ls /mnt/jffs2 profile 6. 卸载文件系统 /#umount l /mnt/jffs2 /#df Filesystem lk-blocks Used Available Use% Mounted on Rootfs %/ /dev/root %/ 这时 NOR Flash 的分区已被卸载 7. 在 /mnt/jffs2/ 目录下已无 Profile 文件 /#cd /mnt/jffs2 /mnt/jffs2 # ls 再挂载分区后又能看到 profile 文件 /#mount t jffs2 /dev/mtdblock2 /mnt/jffs2 /#cd /mnt/jffs2 /mnt/jffs2 # ls profile TEL: FAX: 技术社区 :

186 6.5 SEP4020 Linux 网络设备驱动 M 以太网硬件原理图 硬件原理图如下 图 驱动源码文件位置 SEP4020 的网卡驱动的文件是 /linux/drivers/net/arm/sep_eth.c 和 /linux/drivers/net/arm/sep_eth.h 这两个文件,sep_eth.c 是实现部分,sep_eth.h 是数 据结构定义部分 内核编译相关选项 Device Drivers->Network Device Support->PHY device support->phy device support and infrastructure TEL: FAX: 技术社区 :

187 图 图 TEL: FAX: 技术社区 :

188 图 在 PHY device support 菜单下选取 PHY 设备的支持 图 回到上一级菜单中, 并进入 Ethernet(10 or 100Mbit) 菜单, 在这里选择相 应网卡的支持, 在这里选择 SEP4020 Ethernet 网卡的支持 TEL: FAX: 技术社区 :

189 图 图 这只是选择网络硬件的支持, 现在还需要选择网络协议的支持, 为此还得进 入主菜单中的 Nerworking 选项中, 在这里我们要选取相应的网络协议栈的支持 TEL: FAX: 技术社区 :

190 图 图 TEL: FAX: 技术社区 :

191 图 按照截图中的星号选上相应的选项, 这样基本上就将关于网络的相应设备和协议都选到内核中去了 这样保存退出, 并接着输入 make 命令就可以生成包含网络驱动的新的系统镜像了 网络应用程序接口与样例 由于网络是一个特殊的设备, 而且也是 linux 所依赖的一个标准设备, 所以它的应用程序是可以标准化的, 我们这里以网络标准 socket 编程为例来讲下 linux 下网络的强大应用 什么是 Socket Socket 接口是 TCP/IP 网络的 API,Socket 接口定义了许多函数或例程, 程序员可以用它们来开发 TCP/IP 网络上的应用程序 要学 Internet 上的 TCP/IP 网络编程, 必须理解 Socket 接口 网络的 Socket 数据传输是一种特殊的 I/O,Socket 也是一种文件描述符 Socket 也具有一个类似于打开文件的函数调用 Socket(), 该函数返回一个整型的 Socket 描述符, 随后的连接建立 数据传输等操作都是通过该 Socket 实现的 常用 Socket 类型有两种 : 流式 Socket(SOCK_STREAM) 和数据报式 Socket (SOCK_DGRAM) 流式是一种面向连接的 Socket, 针对于面向连接的 TCP 服务应用 ; 数据报式 Socket 是一种无连接的 Socket, 对应于无连接的 UDP 服务应用 TEL: FAX: 技术社区 :

192 Socket 建立 为了建立 Socket, 程序可以调用 Socket 函数, 该函数返回一个类似于文件描述符的句柄 socket 函数原型为 : int socket(int domain, int type, int protocol); domain 指明所使用的协议族, 通常为 PF_INET, 表示互联网协议族 (TCP/IP 协议族 );type 参数指定 socket 的类型 : SOCK_STREAM 或 SOCK_DGRAM,Socket 接口还定义了原始 Socket(SOCK_RAW), 允许程序使用低层协议 ;protocol 通常赋值 "0" Socket() 调用返回一个整型 socket 描述符, 你可以在后面的调用使用它 Socket 描述符是一个指向内部数据结构的指针, 它指向描述符表入口 调用 Socket 函数时,socket 执行体将建立一个 Socket, 实际上 " 建立一个 Socket" 意味着为一个 Socket 数据结构分配存储空间 Socket 执行体为你管理描述符表 两个网络程序之间的一个网络连接包括五种信息 : 通信协议 本地协议地址 本地主机端口 远端主机地址和远端协议端口 Socket 数据结构中包含这五种信息 Bind 函数将 socket 与本机上的一个端口相关联, 随后你就可以在该端口监听服务请求 Bind 函数原型为 : int bind(int sockfd,struct sockaddr *my_addr, int addrlen); Sockfd 是调用 socket 函数返回的 socket 描述符,my_addr 是一个指向包含有本机 IP 地址及端口号等信息的 sockaddr 类型的指针 ;addrlen 常被设置为 sizeof(struct sockaddr) 面向连接的客户程序使用 Connect 函数来配置 socket 并与远端服务器建立一个 TCP 连接, 其函数原型为 : int connect(int sockfd, struct sockaddr *serv_addr,int addrlen); Sockfd 是 socket 函数返回的 socket 描述符 ;serv_addr 是包含远端主机 IP 地址和端口号的指针 ;addrlen 是远端地址结构的长度 Connect 函数在出现错误时返回 -1, 并且设置 errno 为相应的错误码 进行客户端程序设计无须调用 bind(), 因为这种情况下只需知道目的机器的 IP 地址, 而客户通过哪个端口与服务器建立连接并不需要关心,socket 执行体为你的程序自动选择一个未被占用的端口, 并通知你的程序数据什么时候到打端口 Connect 函数启动和远端主机的直接连接 只有面向连接的客户程序使用 socket 时才需要将此 socket 与远端主机相连 无连接协议从不建立直接连接 TEL: FAX: 技术社区 :

193 面向连接的服务器也从不启动一个连接, 它只是被动的在协议端口监听客户的请求 Listen 函数使 socket 处于被动的监听模式, 并为该 socket 建立一个输入数据队列, 将到达的服务请求保存在此队列中, 直到程序处理它们 int listen(int sockfd, int backlog); Sockfd 是 Socket 系统调用返回的 socket 描述符 ;backlog 指定在请求队列中允许的最大请求数, 进入的连接请求将在队列中等待 accept() 它们 ( 参考下文 ) Backlog 对队列中等待服务的请求的数目进行了限制, 大多数系统缺省值为 20 如果一个服务请求到来时, 输入队列已满, 该 socket 将拒绝连接请求, 客户将收到一个出错信息 accept() 函数让服务器接收客户的连接请求 在建立好输入队列后, 服务器就调用 accept 函数, 然后睡眠并等待客户的连接请求 int accept(int sockfd, void *addr, int *addrlen); sockfd 是被监听的 socket 描述符,addr 通常是一个指向 sockaddr_in 变量的指针, 该变量用来存放提出连接请求服务的主机的信息 ( 某台主机从某个端口发出该请求 );addrten 通常为一个指向值为 sizeof(struct sockaddr_in) 的整型指针变量 出现错误时 accept 函数返回 -1 并置相应的 errno 值 数据传输 Send() 和 recv() 这两个函数用于面向连接的 socket 上进行数据传输 Send() 函数原型为 : int send(int sockfd, const void *msg, int len, int flags); Sockfd 是你想用来传输数据的 socket 描述符 ;msg 是一个指向要发送数据的指针 ;Len 是以字节为单位的数据的长度 ;flags 一般情况下置为 0( 关于该参数的用法可参照 man 手册 ) Send() 函数返回实际上发送出的字节数, 可能会少于你希望发送的数据 在程序中应该将 send() 的返回值与欲发送的字节数进行比较 当 send() 返回值与 len 不匹配时, 应该对这种情况进行处理 char *msg = "Hello!"; int len, bytes_sent; len = strlen(msg); bytes_sent = send(sockfd, msg,len,0); TEL: FAX: 技术社区 :

194 recv() 函数原型为 : int recv(int sockfd,void *buf,int len,unsigned int flags); Sockfd 是接受数据的 socket 描述符 ;buf 是存放接收数据的缓冲区 ;len 是缓冲的长度 Flags 也被置为 0 Recv() 返回实际上接收的字节数, 当出现错误时, 返回 -1 并置相应的 errno 值 Sendto() 和 recvfrom() 用于在无连接的数据报 socket 方式下进行数据传输 由于本地 socket 并没有与远端机器建立连接, 所以在发送数据时应指明目的地址 sendto() 函数原型为 : int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen); 该函数比 send() 函数多了两个参数,to 表示目地机的 IP 地址和端口号信息, 而 tolen 常常被赋值为 sizeof (struct sockaddr) Sendto 函数也返回实际发送的数据字节长度或在出现发送错误时返回 -1 Recvfrom() 函数原型为 : int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen); from 是一个 struct sockaddr 类型的变量, 该变量保存源机的 IP 地址及端口号 fromlen 常置为 sizeof (struct sockaddr) 当 recvfrom() 返回时,fromlen 包含实际存入 from 中的数据字节数 Recvfrom() 函数返回接收到的字节数或当出现错误时返回 -1, 并置相应的 errno 如果你对数据报 socket 调用了 connect() 函数时, 你也可以利用 send() 和 recv() 进行数据传输, 但该 socket 仍然是数据报 socket, 并且利用传输层的 UDP 服务 但在发送或接收数据报时, 内核会自动为之加上目地和源地址信息 结束传输 当所有的数据操作结束以后, 你可以调用 close() 函数来释放该 socket, 从而停止在该 socket 上的任何数据操作 :close(sockfd); 你也可以调用 shutdown() 函数来关闭该 socket 该函数允许你只停止在某个方向上的数据传输, 而一个方向上的数据传输继续进行 如你可以关闭某 socket 的写操作而允许继续在该 socket 上接受数据, 直至读入所有数据 int shutdown(int sockfd,int how); Sockfd 是需要关闭的 socket 的描述符 参数 how 允许为 shutdown 操作选 TEL: FAX: 技术社区 :

195 择以下几种方式 : 不允许继续接收数据 ; 不允许继续发送数据 ; 不允许继续发送和接收数据 ; 均为允许则调用 close (); shutdown 在操作成功时返回 0, 在出现错误时返回 -1 并置相应 errno Socket 编程实例 代码实例中的服务器通过 socket 连接向客户端发送字符串 "Hello, you are connected!" 只要在服务器上运行该服务器软件, 在客户端运行客户软件, 客户端就会收到该字符串 该服务器软件代码如下 : #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/wait.h> #define SERVPORT 3333 /* 服务器监听端口号 */ #define BACKLOG 10 /* 最大同时连接请求数 */ main() { int sockfd,client_fd; /*sock_fd: 监听 socket;client_fd: 数据传输 socket */ struct sockaddr_in my_addr; /* 本机地址信息 */ struct sockaddr_in remote_addr; /* 客户端地址信息 */ if ((sockfd = socket(af_inet, SOCK_STREAM, 0)) == -1) { perror("socket 创建出错!"); exit(1); my_addr.sin_family=af_inet; my_addr.sin_port=htons(servport); my_addr.sin_addr.s_addr = INADDR_ANY; TEL: FAX: 技术社区 :

196 bzero(&(my_addr.sin_zero),8); if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) { perror("bind 出错!"); exit(1); if (listen(sockfd, BACKLOG) == -1) { perror("listen 出错!"); exit(1); while(1) { sin_size = sizeof(struct sockaddr_in); if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size)) == -1) { perror("accept 出错 "); continue; printf("received a connection from %s\n", inet_ntoa(remote_addr.sin_addr)); if (!fork()) { /* 子进程代码段 */ if (send(client_fd, "Hello, you are connected!\n", 26, 0) == -1) perror("send 出错!"); close(client_fd); exit(0); close(client_fd); 服务器的工作流程是这样的 : 首先调用 socket 函数创建一个 Socket, 然后调用 bind 函数将其与本机地址以及一个本地端口号绑定, 然后调用 listen 在相应的 socket 上监听, 当 accpet 接收到一个连接服务请求时, 将生成一个新的 socket 服务器显示该客户机的 IP 地址, 并通过新的 socket 向客户端发送字符串 "Hello,you are connected!" 最后关闭该 socket 代码实例中的 fork() 函数生成一个子进程来处理数据传输部分,fork() 语 TEL: FAX: 技术社区 :

197 句对于子进程返回的值为 0 所以包含 fork 函数的 if 语句是子进程代码部分, 它与 if 语句后面的父进程代码部分是并发执行的 客户端程序代码如下 : #include<stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #define SERVPORT 3333 #define MAXDATASIZE 100 /* 每次最大数据传输量 */ main(int argc, char *argv[]){ int sockfd, recvbytes; char buf[maxdatasize]; struct hostent *host; struct sockaddr_in serv_addr; if (argc < 2) { fprintf(stderr,"please enter the server's hostname!\n"); exit(1); if((host=gethostbyname(argv[1]))==null) { herror("gethostbyname 出错!"); exit(1); if ((sockfd = socket(af_inet, SOCK_STREAM, 0)) == -1){ perror("socket 创建出错!"); exit(1); serv_addr.sin_family=af_inet; serv_addr.sin_port=htons(servport); serv_addr.sin_addr = *((struct in_addr *)host->h_addr); TEL: FAX: 技术社区 :

198 bzero(&(serv_addr.sin_zero),8); if (connect(sockfd, (struct sockaddr *)&serv_addr, \ sizeof(struct sockaddr)) == -1) { perror("connect 出错!"); exit(1); if ((recvbytes=recv(sockfd, buf, MAXDATASIZE, 0)) ==-1) { perror("recv 出错!"); exit(1); buf[recvbytes] = '\0'; printf("received: %s",buf); close(sockfd); 客户端程序首先通过服务器域名获得服务器的 IP 地址, 然后创建一个 socket, 调用 connect 函数与服务器建立连接, 连接成功之后接收从服务器发送过来的数据, 最后关闭 socket 函数 gethostbyname() 是完成域名转换的 由于 IP 地址难以记忆和读写, 所以为了方便, 人们常常用域名来表示主机, 这就需要进行域名和 IP 地址的转换 函数原型为 : struct hostent *gethostbyname(const char *name); 函数返回为 hosten 的结构类型, 它的定义如下 : struct hostent { char *h_name; /* 主机的官方域名 */ char **h_aliases; /* 一个以 NULL 结尾的主机别名数组 */ int h_addrtype; /* 返回的地址类型, 在 Internet 环境下为 AF-INET */ int h_length; /* 地址的字节长度 */ char **h_addr_list; /* 一个以 0 结尾的数组, 包含该主机的所有地址 */ ; #define h_addr h_addr_list[0] /* 在 h-addr-list 中的第一个地址 */ 当 gethostname() 调用成功时, 返回指向 struct hosten 的指针, 当调用失败时返回 -1 当调用 gethostbyname 时, 你不能使用 perror() 函数来输出错误信息, 而应该使用 herror() 函数来输出 TEL: FAX: 技术社区 :

199 6.6 GPIO 通用驱动 驱动源码位置 /linux/drivers/char/sep4020_char/sep4020_gpio.c 内核编译相关选项 Device Drivers->Character Devices->Sep4020 Char Devices->sep4020 led gpio drivers 图 TEL: FAX: 技术社区 :

200 图 图 TEL: FAX: 技术社区 :

201 图 应用程序接口 在 Linux 操作系统中, 所有的设备都被统一成文件, 通过对文件的访问方式 ( 首先 open, 然后 read/write, 同时可以使用 ioctl 读取 / 设置参数, 最后 close) 来访问设备 通用 GPIO 驱动提供了一种 write 操作用来对 sep4020 的 97 个 GPIO 进行写 应用举例 : 流水灯 #include<stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define HIGH 1 #define LOW 0 #define A 0X41 #define B 0x42 #define C 0x43 #define D 0x44 #define E 0x45 #define F 0x46 #define G 0x47 #define H 0x48 #define I 0x49 struct gpio_config // 用来传递 GPIO 端口信息 { TEL: FAX: 技术社区 :

202 int port; // 端口组别, 请用大写的 ABCDEFGHI 来标识 int num;// 端口号 int data;// 需要传递参数 ; int main(int argc, char **argv){ int fd,i,j; struct gpio_config *config; config = malloc(sizeof(struct gpio_config)); config->port = E; // 端口号请用大写的字母 fd=open("/dev/sep4020_gpio",o_rdwr); if(fd==-1) { printf("wrong\r\n"); exit(-1); j = 0; i = 0; while(1) { i++; j = i%5; config->num = j; config->data = 1; write(fd,config,12);// 这儿写的结构体长度固定为 12 个字节, 也就是 3 个整形变量 sleep(1); config->data = 0; write(fd,config,12); sleep(1); close(fd); return 0; TEL: FAX: 技术社区 :

203 6.7 STN 驱动 硬件原理图如下 : 图 驱动源码位置 /linux/drivers/char/sep4020_char/sep4020_grylcd.c 内核编译相关选项 Device Driver->Graphics support->sep *480 LCD support-> SEP *240 LCD support TEL: FAX: 技术社区 :

204 图 图 TEL: FAX: 技术社区 :

205 图 Device Driver->Graphics support->console display driver-support 图 Device Driver->Graphics support->logo configuration TEL: FAX: 技术社区 :

206 图 应用程序接口与程序样例 int main() { unsigned char pagedata[1320]; int k=0; unsigned char i,j; unsigned char font[100]={0x00,40,10,5,0x20,0x10,0xfc,0x03, 0x10,0xCC,0x07,0xF4,0x04,0x54,0x8C,0x04, 0x00,0x00,0x0F,0X02,0x01,0x04,0x08,0x07,0x00,0x00,0x00,0x03,; char ch[5]; lcd_open(); //open("/dev/graylcd",o_rdwr); printf("\n\n*******this is a demo of the LCD driver*********\n\n"); lp: printf("[a] demo of drawing a square\n"); printf("[b] demo of filling a square\n"); printf("[c] demo of drawing an ellipse\n"); printf("[d] demo of filling an ellipse\n"); printf("[e] demo of drawing a line\n"); printf("[f] demo of all display characters\n"); printf("[g] demo of copying pictures and displaying it\n"); printf("[h] demo of displaying the icon\n"); printf("[i] showing all the demos\n"); printf("[j] demo of reversing mode parameter and set pixel,\nreverse the displayed contents\n"); printf("[k] clear the screen\n"); printf("[l] demo of the caret\n"); printf("[m] exit the demo\n\n"); TEL: FAX: 技术社区 :

207 scanf("%s",ch); if(strcmp(ch,"c")==0) draw_ellipse(16,30,15,8,1); // 画一个椭圆, 五个参数分别为 x,y 轴中点, // x,y 轴中点, 设置像素 if(strcmp(ch,"d")==0) fill_ellipse(50,32,10,15,1); // 填充椭圆 if(strcmp(ch,"a")==0) draw_rect(70,20,20,20,1); // 画一个正方形, 五个参数分别为起始点的 x,y // 坐标,x,y 轴的长度, 设置像素 if(strcmp(ch,"b")==0) fill_rect(100,20,10,20,1); // 填充一个长方形 if(strcmp(ch,"e")==0) draw_line(125,60,100,2); // 画一条直线, 参数分别为起点的 x,y 坐标, // 终点的 x,y 坐标 if(strcmp(ch,"f")==0) text_out(0,48,"demo of 椭圆矩形复制 "); // 打印一组字符, 参数为起始处 x,y 坐标, // 打印内容 if(strcmp(ch,"g")==0) { save_rect(pagedata,0,48,120,16);// 存储图形到指定区域, 参数分别数组存储区, // 起始处的 x,y 坐标, 图形宽度和高度 paint_rect(pagedata,0,1,120,16); // 画图形 if(strcmp(ch,"h")==0) { set_icon(5,i); // 显示图标 if(i==0) i=1; else i=0; if(strcmp(ch,"j")==0) { for(i=0;i<131;i++) for(j=0;j<63;j++) set_pixel(i,j,2); if(strcmp(ch,"i")==0) { TEL: FAX: 技术社区 :

208 draw_ellipse(16,30,15,8,1); fill_ellipse(50,32,10,15,1); draw_rect(70,20,20,20,1); fill_rect(100,20,10,20,1); draw_line(125,60,100,2); text_out(0,48,"demo of 椭圆矩形复制 "); save_rect(pagedata,0,48,120,16); paint_rect(pagedata,0,1,120,16); //set_icon(7,k=~k); //set_icon(8,k=~k); if(strcmp(ch,"k")==0) lcd_clear(); if(strcmp(ch,"l")==0) set_caret(15,15,5,10,1); if(strcmp(ch,"m")!=0) goto lp; lcd_close(); return 0; // 清屏 // 关 LCD TEL: FAX: 技术社区 :

209 第七章 Linux 应用程序开发 本节内容通过嵌入式 Linux 开发最简单的例子, 介绍了如何编写和编译 Linux 应用程序, 并下载到开发板运行起来 7.1 Linux 应用程序快速入门 编写源代码 helloworld.c 在 /root/ 下建一个自己的目录 : #mkdir code #cd code #vim helloworld.c #include<stdio.h> int main(void) { printf("we love arm,we love sep4020!!\n"); 编译 helloworld.c (1) 在 pc 机上编译能在 pc 机上运行的应用程序的方法 : # gcc o helloworld_pc helloworld.c ( 这个是用 i386 的 gcc 编译器编译的, 所以只能在 pc 机的 linux 环境中运行 ) (2) 在 pc 机上编译能在 sep4020 板子上运行的应用程序的方法 : #arm-linux-gcc o helloworld_arm helloworld.c ( 这个是用 arm 的交叉 gcc 编译器编译的, 所以可以下载到板子上运行 ) 运行 helloworld 程序 将编译好的可执行文件下载到目标板目前主要三种方式 : 复制到介质 ( 如优盘 ); TEL: FAX: 技术社区 :

210 通过网络传送文件到开发板 ( 如 tftp 传送 ); 通过 NFS( 网络文件系统 ) 直接运行 (1) 在 pc 机上运行 i386 的程序 下面先在 pc 机上运行 helloworld_pc: [root@localhost code]#./helloworld_pc We love arm,we love sep4020!! (2) 在开发板上运行应用程序 将应用程序 helloworld_arm 拷贝到 /nfs/demo 文件夹下 ( 可以再虚拟机中直接复制, 粘贴 ): [root@localhost code]# cp helloworld_arm /nfs/demo 将开发板上电, 挂载网络文件系统 /nfs, 然后就可以在板子上运行应用程序了 : / # cd demo /demo #./helloworld_arm We love arm,we love sep4020!! 所有的操作过程 ( 如图 7.1) 所示 图 7.1 注意 : 一定要先看下 /nfs/lib 下有没有 libc.so 这个库文件, 没有的话要从交叉编译器的目录中拷贝过来, 否则就会报如下错误 : /demo #./helloworld_arm -/bin/sh:./helloworld_arm: not found TEL: FAX: 技术社区 :

211 7.2 MiniGUI 程序开发简介 MiniGUI 交叉编译过程 交叉编译的准备工作 在开始之前, 先准备好交叉编译过程中所需要的几个库文件 : 交叉编译器 :arm-linux-gcc jpegsrc.v6b.tar.gz 2. libpng tar.bz2 3. mde tar.gz 4. popt-1.7.tar.gz 5. tslib-1.3.tar.bz2 6. libminigui tar.gz 7. minigui-res tar.gz 8. zlib tar.gz 9. freetype tar.gz MiniGUI 的安装与配置过程 第一步 : 首先建立新目录 [root@localhost /]# mkdir -p /root/cross 将开头所述的文件全部拷贝至 /root/cross 目录下第二步 : 安装 zlib 库, 这个是后面的库的编译基础 [root@localhost cross]# tar zxvf zlib tar.gz 由于 zlib 库的 configure 脚本不支持交叉编译选项, 只好自己手动临时把 gcc 修改成指向我们的交叉编译器 arm-linux-gcc [root@localhost cross]# cd /usr/bin/ [root@localhost bin]# mv gcc gcc_back [root@localhost bin]# ln -s /usr/local/arm/3.4.1/bin/arm-linux-gcc./gcc [root@localhost bin]# mv ld ld_back [root@localhost bin]# ln -s /usr/local/arm/3.4.1/bin/arm-linux-ld./ld 修改完成后回到 /root/cross/zlib 目录下 : [root@localhost bin]# cd /root/cross/zlib [root@localhost zlib-1.2.3]#./configure --prefix=/usr/local/arm/3.4.1/arm-linux --shared 注意 : 这里配置指向 /usr/local/arm/3.4.1/arm-linux 目录, 会自动安装在 /usr/local/arm/3.4.1/arm-linux / [include,lib] 目录下 [root@localhost zlib-1.2.3]# make TEL: FAX: 技术社区 :

212 zlib-1.2.3]# make install 安装完后检查一下目录 /usr/local/arm/3.4.1/arm-linux / [include,lib], 假如 include 中没有 zlib.h 之类的头文件,lib 中没有 libz.so.1.2.3, 那就自己手动拷到这些目录下去, 记着拷的时候把所有的 *.h 都需要拷过去, 在拷库的时候用 cp a libz.* /./lib 就行, 要用上 a 选项注意 : 记着把刚才改过的 gcc 再改回去, 不然后面会出错的!!!!!( 一定记得改 ) [root@localhost zlib-1.2.3]# cd /usr/bin/ [root@localhost bin]# mv gcc_back gcc mv: 是否覆盖 gcc? y [root@localhost bin]# mv ld_back ld mv: 是否覆盖 ld? y 第三步 : 安装 png 库, 这个是用来显示 png 图形的,MiniGUI 里很多图都是 png 的, 如果没有这个库, 你的 MiniGUI 将无法正常工作 [root@localhost bin]# cd /root/cross/ [root@localhost cross]# tar xjvf libpng tar.bz2 [root@localhost libpng ]# cd libpng [root@localhost libpng ]#./configure CC=arm-linux-gcc --build=i686-pc-linux --target=arm-linux --host=arm-linux prefix=/usr/local/arm/3.4.1/arm-linux [root@localhost libpng ]# make [root@localhost libpng ]# make install 安装结束后, 查看下 /usr/local/arm/3.4.1/arm-linux/ 目录下的 lib 文件夹里是否有 libpng.a,libpng.so 等文件和 include 文件夹里是否有 png.h, pngconf.h 文件以及 libpng12 文件夹 第四步 : 安装 jpeg 库 [root@localhost libpng ]# cd /root/cross/ [root@localhost cross]# tar zxvf jpegsrc.v6b.tar.gz [root@localhost cross]# cd jpeg-6b/ [root@localhost jpeg-6b]#./configure CC=arm-linux-gcc --build=i686-pc-linux --target=arm-linux --host=arm-linux prefix=/usr/local/arm/3.4.1/arm-linux --enable-shared 注意 : 在 make 之前, 需从前面 libpng 的源码目录中把 libtool 拷贝过来, 放在 /home/source/minigui/jpeg-6b 目录下, 否则会出错 [root@localhost jpeg-6b]# cp../libpng /libtool. [root@localhost jpeg-6b]# make 注意 : 在 make install 之前需创建一个目录, 否则 make install 的时候会报错 TEL: FAX: 技术社区 :

213 jpeg-6b]# mkdir -p /usr/local/arm/3.4.1/arm-linux/man/man1 jpeg-6b]# make install 安装结束后, 查看下 /usr/local/arm/3.4.1/arm-linux/ 目录下的 lib 文件夹里是否有 libjpeg.so,libjpeg.so 等文件和 include 文件夹里是否有 jpeglib.h 文件第五步 : 安装 libttf 库, 这个是 TrueType 字体的支持库, 用来显示文字的 注意 :MiniGUI 的文档说只支持 版本的 ttf 库, 不要把版本弄错了 [root@localhost jpeg-6b]# cd /root/cross/ [root@localhost cross]# tar zxvf freetype tar.gz [root@localhost cross]# cd freetype [root@localhost freetype-1.3.1]# mkdir -p /root/cross/libttf/extend [root@localhost freetype-1.3.1]# cp./lib/*./lib/arch/ansi/* /root/cross/libttf/ cp: 略过目录./lib/arch cp: 略过目录./lib/extend [root@localhost freetype-1.3.1]# cp./lib/extend/* /root/cross/libttf/extend/ [root@localhost freetype-1.3.1]# cd../libttf/ [root@localhost libttf]# arm-linux-gcc -c -fpic -O2 freetype.c [root@localhost libttf]# arm-linux-gcc -c -fpic -O2 -I./ extend/*.c [root@localhost libttf]# arm-linux-gcc --shared -o libttf.so *.o 现在手动安装, 得自己建立一下目录 : [root@localhost libttf]# mkdir -p /usr/local/arm/3.4.1/arm-linux/include/freetype1/freetype [root@localhost libttf]# cp *.h extend/*.h /usr/local/arm/3.4.1/arm-linux/include/freetype1/freetype [root@localhost libttf]# cp libttf.so /usr/local/arm/3.4.1/arm-linux/lib 安装库完成 第六步 : 编译安装 minigui 资源包 minigui-res [root@localhost libttf]# cd /root/cross/ [root@localhost cross]# tar zxvf minigui-res tar.gz [root@localhost cross]# cd minigui-res [root@localhost minigui-res ]# make install 注意 : 在 /usr/local/lib 目录下生成一个 minigui 目录, 切记后面一定要将此处的资源包拷过去第七步 : 配置编译安装 MiniGUI MiniGUI 版本在链接 ljpeg lpng 时总是要链接 /usr/lib 下的库, 没办法, 只好用前面的方法, 使用备份和软连接的方法 TEL: FAX: 技术社区 :

214 cross]# cd /usr/lib lib]# mv libjpeg.so libjpeg.so_back lib]# mv libpng.so libpng.so_back lib]# cp /usr/local/arm/3.4.1/arm-linux/lib/libttf.so. lib]# ln -s /usr/local/arm/3.4.1/arm-linux/lib/libpng.so./libpng.so lib]# ln -s /usr/local/arm/3.4.1/arm-linux/lib/libjpeg.so./libjpeg.so cross]# cd /root/cross/ cross]# tar zxvf libminigui tar.gz cross]# cd libminigui libminigui ]#./configure CC=arm-linux-gcc --build=i686-pc-linux --target=arm-linux --host=arm-linux --disable-galqvfb --disable-galecoslcd --disable-vbfsupport --disable-ttfsupport --disable-type1support --prefix=/usr/local/arm/3.4.1/arm-linux 配置之后, 进行编译安装 : [root@localhost libminigui ]# make [root@localhost libminigui ]# make install 安装结束后, 查看下 /usr/local/arm/3.4.1/arm-linux/ 目录下的 lib 文件夹里是否有 libminigui.so, libmgext.so, libvcongui.so 等文件和 include 文件夹里是否有 minigui 文件夹 ( 内有 minigui 相关的头文件 ) 注意 : 现在不要忘记把前面刚刚备份的改回来 [root@localhost libminigui ]# cd /usr/lib [root@localhost lib]# mv libjpeg.so_back libjpeg.so mv: 是否覆盖 libjpeg.so? y [root@localhost lib]# mv libpng.so_back libpng.so mv: 是否覆盖 libpng.so? y 注意 : 现在把上面编译的资源包 /usr/local/lib/minigui/ 下的 res 目录拷到 /usr/local/arm/3.4.1/arm-linux/lib/minigui/ 下!!!!!!!!!!!! [root@localhost libminigui ]# cp -a /usr/local/lib/minigui/res/ /usr/local/arm/3.4.1/arm-linux/lib/minigui/ 第八步 : 安装 popt 库, 这个库在编译 mde 程序时需要使用, 不然编译没法通过 [root@localhost libminigui ]# cd /root/cross/ [root@localhost cross]# tar zxvf popt-1.7.tar.gz [root@localhost cross]# cd popt-1.7 [root@localhost popt-1.7]#./configure CC=arm-linux-gcc --build=i686-pc-linux TEL: FAX: 技术社区 :

215 --target=arm-linux --host=arm-linux prefix=/usr/local/arm/3.4.1/arm-linux --enable-shared --enable-shared --enable-static popt-1.7]# make popt-1.7]# make install 安装结束后, 查看下 /usr/local/arm/3.4.1/arm-linux/ 目录下的 lib 文件夹里是否有 libpopt.a,libpopt.la,libpopt.so 等文件和 include 文件夹里是否有 popt.h 文件 第九步 : 编译综合例子 mde [root@localhost popt-1.7]# cd /root/cross/ [root@localhost cross]# tar zxvf mde tar.gz [root@localhost cross]# cd mde [root@localhost mde ]#./configure CC=arm-linux-gcc --build=i686-pc-linux --target=arm-linux --host=arm-linux [root@localhost mde ]# make MiniGUI 的移植 1) 库文件把 /usr/local/arm/3.4.1/arm-linux/lib 中相应的库拷到 nfs/lib 目录下去, 可以直接将整个 /usr/local/arm/3.4.1/arm-linux/lib 拷到 nfs 下面 : [root@localhost cross]# cp -ar /usr/local/arm/3.4.1/arm-linux/lib /nfs 去掉其中.a 文件 : [root@localhost cross]# rm -rf /nfs/lib/*.a OK, 库文件准备完毕 2) 资源文件下面把资源文件也拷过来, 在前面搭建 PC 环境中讲过安装资源文件, 它被装在了 /usr/local/lib 目录下, 一个叫 minigui 的目录, 我们要做的就是把它拷过来 : [root@localhost cross]# cp -ar /usr/local/lib/minigui /nfs/lib/minigui 3) 配置文件将配置文件也拷过来 : 因为 /nfs/usr 下没有目录, 所以我们需新建目录 : [root@localhost cross]# mkdir -p /nfs/usr/local/etc [root@localhost cross]# cp /usr/local/arm/3.4.1/arm-linux/etc/minigui.cfg /nfs/usr/local/etc/ [root@localhost cross]# cd /nfs/usr/local/etc/ 修改 MiniGUI.cfg [root@localhost etc]# gedit MiniGUI.cfg TEL: FAX: 技术社区 :

216 [system] # GAL engine gal_engine=fbcon [system] # IAL engine ial_engine=dummy// 这里修改, 我用的是触摸屏, 所以就用 dummy 肯定不会错 mdev=/dev/tp // 触摸屏 mtype=none [fbcon] defaultmode=320x240-16bpp // 根据你的 LCD 大小自己设置注意 : 然后, 需将文件中的所有 /usr/local/ 替换为 / ial_engine 一开始建议用 dummy, 先让 minigui 跑起来, 以后再把触摸屏加进去, 保证尽可能减少错误的发生再将 /root/cross/mde / 下的文件夹都拷贝 ( 每一个文件夹都是一个综合实例 ) 到 nfs/demo/ 下面 : [root@localhost etc]# mkdir -p /nfs/demo [root@localhost etc]# cp -ar /root/cross/mde /nfs/demo/ 保存, 退出 OK, 你的板子上的系统也搭建完毕了, 现在可以在屏幕上显示图片了, 但是还不可以用触摸屏进行控制 tslib 移植到 SEP4020 以上已经成功移植了 MiniGUI, 由于不能使用触摸屏来进行控制, 这次将继续上次的移植 往 4020 上移植 tslib 大概方法是通过 tslib 来构建 MiniGUI 的输入引擎 tslib 是一个用于触摸屏设备的函数库, 通过这样一个函数库, 可以将编程者从繁琐的数据处理中解脱出来 因为触摸屏的坐标和液晶显示屏之间的坐标并不是一一对应的, 所以, 要让从触摸屏上得到的坐标正确转换为液晶显示屏上的坐标, 需要经过一个转换过程 除此之外,tslib 还以插件的形式提供了一些附加的功能, 比如去除点击触摸屏时的抖动等第一步 : 下载源文件并解压 [root@localhost cross]# tar xjvf tslib-1.3.tar.bz2 [root@localhost cross]# cd tslib-1.3 第二步 : 针对底层驱动修改配置信息 [root@localhost tslib-1.3]#./autogen.sh ( 这步会生产 configure 文件 ) [root@localhost tslib-1.3]#./configure CC=arm-linux-gcc --build=i686-pc-linux --target=arm-linux --host=arm-linux --prefix=/usr/local/arm/3.4.1/arm-linux --enable-inputapi=no 第三步 : 修改源码 修改 /root/cross/tslib-1.3 /plugins/makefile 里面 LDFLAGS: TEL: FAX: 技术社区 :

217 tslib-1.3]# cd plugins/ plugins]# gedit Makefile 将第 143 行的 LDFLAGS :=$(LDFLAGS) -rpath $(PLUGIN_DIR) 修改为 : LDFLAGS :=$(LDFLAGS) -rpath `cd $(PLUGIN_DIR) && pwd`( 这个可是顿号 ) 修改在 /root/cross/tslib-1.3 /plugins/mousebuts.c 的 mousebuts_read 函数中一段代码 : [root@localhost plugins]# gedit mousebuts.c 将第 67 行到 70 行注释掉, 第 73 行注释掉 : //if (t > 60) { //dest->pressure = 1000; //buts->fleftbut = 0; // else { dest->pressure = 0; buts->fleftbut = 2; // 否则以后运行 minigui 时对按钮的操作时, 如果对一个按钮进行点击时, 并把光标停在按钮的上面它就会不断的触发按钮的点击事件, 这当然不是我们想要得到的结果 修改 /root/cross/tslib-1.3 /src/ts_read_raw.c 中的一段代码 : [root@localhost plugins]# cd../src/ [root@localhost src]# gedit ts_read_raw.c 将第 98 行中的 char *defaulttseventtype="ucb1x00"; 改为 char *defaulttseventtype="h3600"; 因为我的触摸屏驱动对应此结构 修改 ts_read_raw.c 在 197 行后添加一行 :ret=sizeof(*hevt); 结果如下 : #else tseventtype = getenv("tslib_tseventtype"); if(tseventtype==null) tseventtype=defaulttseventtype; if( strcmp(tseventtype,"h3600") == 0) { /* ipaq style h3600 touchscreen events */ hevt = alloca(sizeof(*hevt) * nr); ret = read(ts->fd, hevt, sizeof(*hevt) * nr); ret=sizeof(*hevt); if(ret > 0) { 要添加红色的这句话, 否则运行./ts_ts_calibrate 会出现以下错误 : /tests #./ts_calibrate enable_irq(1) unbalanced from c0132bdc TEL: FAX: 技术社区 :

218 xres = 640, yres = 480 ts_read: No such file or directory 修改 tslib 源码的 tests/ts_calibrate.c 的 getxy 函数中修改一些代码如下 : [root@localhost src]# cd../tests/ [root@localhost tests]# gedit ts_calibrate.c 在第 59 行处 : /* Read until we get a touch. */ do { if (ts_read_raw(ts, &samp[0], 1) < 0) { perror("ts_read"); close_framebuffer(); exit(1); while (samp[0].pressure > 0); /* Now collect up to MAX_SAMPLES touches into the samp array. */ index = 0; do { if (index < MAX_SAMPLES-1) index++; if (ts_read_raw(ts, &samp[index], 1) < 0) { perror("ts_read"); close_framebuffer(); exit(1); while (samp[index].pressure == 0); printf("took %d samples...\n",index); 发现 tslib 与 minigui 中对于压力参数的规定刚好相反,tslib 规定 samp[0].pressure> 0 是按下,samp[0].pressure == 0 是手松开而事实是相反的如果不改就会出现在运行./ts_calibrate 程序时不能有效校准, 这个一定得注意 第四步 : 编译与安装 [root@localhost tests]# cd.. [root@localhost tslib-1.3]# make [root@localhost tslib-1.3]# make install 第五步 :tslib 移植到嵌入式文件系统上 ts.conf, 应该把它复制到目标板环境变量 TSLIB_CONFFILE 指定的目录下 : [root@localhost tslib-1.3]# cd /usr/local/arm/3.4.1/arm-linux/etc/ [root@localhost etc]# cp ts.conf /nfs/etc/ 将 libts-0.0.so.0 libts -0.0.so libts.so, 这三个文件应该被复制 TEL: FAX: 技术社区 :

219 到目标板的 LD_LIBRARY_PATH 环境变量指定目录下 : [root@localhost etc]# cd../lib 图 7.2 [root@localhost lib]# cp libts-0.0.so.0 libts-0.0.so libts.so /nfs/lib/ [root@localhost lib]# mkdir -p /nfs/test [root@localhost lib]# cp /usr/local/arm/3.4.1/arm-linux/bin/ts* /nfs/test 安装的时候你可能没有看到 plugins 目录, 要在 /usr/local/arm/3.4.1/arm-linux/share/ts/ 下找 : [root@localhost lib]# cp -r /usr/local/arm/3.4.1/arm-linux/share/ts/plugins /nfs 经过这四次拷贝就将 tslib 的相应库都拷全了, 下面要配置文件系统的环境变量, 这样程序才能到指定目录下去找库 : [root@localhost /]# cd /nfs/etc/ [root@localhost etc]# gedit profile 在里面添加以下环境变量 : export T_ROOT=/ export LD_LIBRARY_PATH=/lib export TSLIB_CONSOLEDEVICE=none export TSLIB_TSDEVICE=/dev/tp export TSLIB_CALIBFILE=/etc/pointercal export TSLIB_CONFFILE=/etc/ts.conf export TSLIB_PLUGINDIR=/plugins 使有如下形式 : 第六步 : 生成校准文件 pointercal 在目标板上运行校准程序校准屏幕 (5 点校准 ): /test #./ts_calibrate TEL: FAX: 技术社区 :

220 图 7.3 板子上陆续出现 5 个光标, 点击完毕后会生成校准文件 pintercal 存放在 etc/ 下面 ts_calibrate 是一个应用程序, 在屏幕上画几个按钮, 将用户点击后从 tp 驱动获得的数据和屏上的坐标位置通过一套算法来获得校准数据写到一个校准文件里 pointercal 文件中包含了触摸屏的校准数据 (calibration), 正是由于该文件的存在,tslib 才能正确地在触摸屏坐标和液晶屏幕的坐标之间进行转换 第七步 :tslib 和 minigui 的链接我们需要将 tslib 和 minigui 进行链接, 则可以通过改写 MiniGUI 的 IAL 引擎 MiniGUI 自带的 IAL 输入引擎中, 有一个叫做 dummy.c 存在于 /root/cross/libminigui /src/ial 中, 为了尽可能简单, 在这里为简单起见就在其基础上稍作修改, 使之符合我们的要求即可 其内容如下 : [root@localhost libminigui ]# cd src/ial/ [root@localhost ial]# gedit dummy.c 写入以下内容 : #include <sys/stat.h> #include <linux/kd.h> #include "ial.h" #include "dummy.h" TEL: FAX: 技术社区 :

221 #ifndef _DEBUG #define _DEBUG #endif // for debugging /* for storing data reading from /dev/touchscreen/0raw */ typedef struct { unsigned short pressure; unsigned short x; unsigned short y; unsigned short pad; TS_EVENT; static unsigned char state [NR_KEYS]; static int mousex = 0; static int mousey = 0; static TS_EVENT ts_event; static struct tsdev *ts; /************************ Low Level Input Operations **********************/ /* * Mouse operations -- Event */ static int mouse_update(void) { return 1; static void mouse_getxy(int *x, int* y) { if (mousex < 0) mousex = 0; if (mousey < 0) mousey = 0; TEL: FAX: 技术社区 :

222 if (mousex > 639) mousex = 639; if (mousey > 479) mousey = 479; #ifdef _DEBUG #endif // printf ("mousex = %d, mousey = %d\n", mousex, mousey); *x = mousex; *y = mousey; static int mouse_getbutton(void) { return ts_event.pressure; #ifdef _LITE_VERSION static int wait_event (int which, int maxfd, fd_set *in, fd_set *out, fd_set *except, struct timeval *timeout) #else static int wait_event (int which, fd_set *in, fd_set *out, fd_set *except, struct timeval *timeout) #endif { struct ts_sample sample; int ret = 0; int fd; fd_set rfds; int e; if (!in) { in = &rfds; TEL: FAX: 技术社区 :

223 FD_ZERO (in); fd = ts_fd(ts); if ((which & IAL_MOUSEEVENT) && fd >= 0) { FD_SET (fd, in); #ifdef _LITE_VERSION if (fd > maxfd) maxfd = fd; #endif #ifdef _LITE_VERSION e = select (maxfd + 1, in, out, except, timeout) ; #else e = select (FD_SETSIZE, in, out, except, timeout) ; #endif if (e > 0) { // input events is coming if (fd > 0 && FD_ISSET (fd, in)) { FD_CLR (fd, in); ts_event.x=0; ts_event.y=0; ret = ts_read(ts, &sample, 1); if (ret < 0) { perror("ts_read()"); exit(-1); ts_event.x = sample.x; ts_event.y = sample.y; ts_event.pressure = (sample.pressure > 0? 4:0); TEL: FAX: 技术社区 :

224 // if (ts_event.pressure > 0 && if((ts_event.x >= 0 && ts_event.x <= 639) && (ts_event.y >= 0 && ts_event.y <= 479)) { mousex = ts_event.x; mousey = ts_event.y; // printf("ts_event.x is %d, ts_event.y is %d >\n",ts_event.x,ts_event.y); //#ifdef _DEBUG // if (ts_event.pressure > 0) { // printf ("mouse down: ts_event.x = %d, ts_event.y = %d,ts_event.pressure = %d\n",ts_event.x,ts_event.y,ts_event.pressure); // //#endif ret = IAL_MOUSEEVENT; return (ret); else if (e < 0) { return -1; return (ret); BOOL InitDummyInput(INPUT* input, const char* mdev, const char* mtype) { char *ts_device = NULL; if ((ts_device = getenv("tslib_tsdevice"))!= NULL) { TEL: FAX: 技术社区 :

225 // open touch screen event device in blocking mode ts = ts_open(ts_device, 0); else { #ifdef USE_INPUT_API ts = ts_open("/dev/input/0raw", 0); #else ts = ts_open("/dev/touchscreen/ucb1x00", 0); #endif #ifdef _DEBUG printf ("TSLIB_TSDEVICE is open!!!!!!!!!!!\n"); #endif if (!ts) { perror("ts_open()"); exit(-1); if (ts_config(ts)) { perror("ts_config()"); exit(-1); input->update_mouse = mouse_update; input->get_mouse_xy = mouse_getxy; input->set_mouse_xy = NULL; input->get_mouse_button = mouse_getbutton; input->set_mouse_range = NULL; TEL: FAX: 技术社区 :

226 input->wait_event = wait_event; mousex = 0; mousey = 0; ts_event.x = ts_event.y = ts_event.pressure = 0; return TRUE; void TermDummyInput(void) { if (ts) ts_close(ts); #endif /* _DUMMY_IAL */ 将 dummy.c 修改好以后就可以对 minigui 进行重新编译了, 因为用到了 tslib 库, 所以必须在编译的时候告诉 MiniGUI 到哪里去找到 tslib 相关的头文件和共享库文件 具体做法如下所示 : 第八步 : 重新配置编译安装 MiniGUI [root@localhost cross]# cd /usr/lib [root@localhost lib]# mv libjpeg.so libjpeg.so_back [root@localhost lib]# mv libpng.so libpng.so_back [root@localhost lib]# mv libttf.so libttf.so_back [root@localhost lib]# ln -s /usr/local/arm/3.4.1/arm-linux/lib/libttf.so./libttf.so [root@localhost lib]# ln -s /usr/local/arm/3.4.1/arm-linux/lib/libpng.so./libpng.so [root@localhost lib]# ln -s /usr/local/arm/3.4.1/arm-linux/lib/libjpeg.so./libjpeg.so [root@localhost lib]# cd /root/cross/libminigui [root@localhost libminigui ]#./configure CC=arm-linux-gcc --build=i686-pc-linux --target=arm-linux --host=arm-linux --disable-galqvfb --disable-galecoslcd --disable-vbfsupport --disable-ttfsupport --disable-type1support --prefix=/usr/local/arm/3.4.1/arm-linux CFLAGS="-I/usr/local/arm/3.4.1/arm-linux/include -L/usr/local/arm/3.4.1/arm-linux/lib -lts" [root@localhost libminigui ]# make [root@localhost libminigui ]# make install TEL: FAX: 技术社区 :

227 注意 : 现在不要忘记把前面刚刚备份的改回来 [root@localhost libminigui ]# cd /usr/lib [root@localhost lib]# mv libjpeg.so_back libjpeg.so mv: 是否覆盖 libjpeg.so? y [root@localhost lib]# mv libpng.so_back libpng.so mv: 是否覆盖 libpng.so? y [root@localhost lib]# mv libttf.so_back libttf.so mv: 是否覆盖 libttf.so? y 第九步 : 重新配置编译安装 mde [root@localhost lib]# cd /root/cross/mde [root@localhost mde ]#./configure CC=arm-linux-gcc --build=i686-pc-linux --target=arm-linux--host=arm-linux CFLAGS="-I/usr/local/arm/3.4.1/arm-linux/include -L/usr/local/arm/3.4.1/arm-linux/lib -lts" [root@localhost mde ]# make [root@localhost mde ]# make install 第十步 : 重新拷贝并实验编译完以上两个, 再把 /usr/local/arm/3.4.1/arm-linux 下的 lib 文件夹复制到 /nfs/ 下面 由于以前已将拷贝过一部分, 现在可以将以前的苦删除掉然后重新拷贝 同理先删除 demo 下的实例然后重新拷贝 [root@localhost mde ]# rm -rf /nfs/lib [root@localhost mde ]# cp -rf /usr/local/arm/3.4.1/arm-linux/lib /nfs/ [root@localhost mde ]# rm -rf /nfs/lib/*.a [root@localhost mde ]# rm -rf /nfs/lib/minigui/ [root@localhost mde ]# cp -ar /usr/local/lib/minigui/ /nfs/lib/ [root@localhost mde ]# rm -rf /nfs/demo/mde / [root@localhost mde ]# cp -ar../mde /nfs/demo/ 好了, 重新启动开发板, 现在就可以利用触摸屏来控制 MiniGUI 中的控件了 TEL: FAX: 技术社区 :

228 7.3 SNMP( 简单网络协议 ) 程序开发 SNMP 基本知识 SNMP 的管理模型 SNMP 管理模型中有三个基本组成部分 : 管理者 (Manager), 被管代理 (Agent) 和管理信息库 (MIB) 管理站一般是一个单机设备或一个共享网络中的一员, 它是网络管理员和网络管理系统的接口, 能将网络管理员的命令转换成对网络元素的监视和控制, 同时从网上所有被管实体的 MIB ( 管理信息库 ) 中提取出信息数据 管理者可以通过 SNMP 操作直接与管理代理通信, 获得即时的设备信息, 对网络设备进行配置管理或者操作 ; 也可以通过对数据库的访问获得网络设备的历史信息, 以决定网络配置变化等操作 SNMP 管理代理指的是用于跟踪监测被管理设备状态的特殊软件或硬件, 每个代理都拥有自己本地的 MIB 实际上,SNMP 的管理任务是移交给管理代理来执行的 代理翻译来自管理站的请求, 验证操作的可执行性, 通过直接与相应的功能实体通信来执行信息处理任务, 同时向管理站返回响应信息 管理信息库 (MIB) 信息为网管中被管资源, 而网络管理中的资源是以对象表示的, 每个对象表示被管资源的某方面属性, 这些对象形成了 MIB 库 每个 MIB 变量记录了每个相连网络的状态 通信量统计数据 发生差错的次数以及内部数据结构的当前内容等 网络管理者通过对 MIB 库的存取访问, 来实现管理功能 SNMP 报文种类 SNMP 代理和管理站通过 SNMP 协议中的标准消息进行通信, 每个消息都是一个单独的数据报 SNMP 使用 UDP( 用户数据报协议 ) 作为第四层协议 ( 传输协议 ), 进行无连接操作 SNMP 规定了 5 种协议消息 ( 也就是 SNMP 报文 ), 用来在管理进程和代理之间的交换 Get-Request Get-Next-Request 与 Get-Response SNMP 管理站用 Get-Request 消息从拥有 SNMP 代理的网络设备中检索信息, 而 SNMP 代理则用 Get-Response 消息响应 Get-Next-Request 用于和 Get-Request TEL: FAX: 技术社区 :

229 组合起来查询特定的表对象中的列元素 Set-Request SNMP 管理站用 Set-Request 可以对网络设备进行远程配置 ( 包括设备名 设备属性 删除设备或使某一个设备属性有效 / 无效等 ) Trap SNMP 代理使用 Trap 向 SNMP 管理站发送非请求消息, 一般用于描述某一事件的发生 前面的 Request 操作是由管理进程向代理进程发出的, 后面的 Response 和 Trap 操作是代理进程发给管理进程的, 为了简化起见, 前面 3 个操作今后叫做 get get-next 和 set 操作 在代理进程端是用熟知端口 161 来接收 get 或 set 报文, 而在管理进程端是用熟知端口 162 来接收 trap 报文 开发实现 在 SEP4020 测试中, 可以使用 SNMP 工具检测 MIB 库中自带的信息, 比如 system 信息 ; 还可以自定义 MIB 模块文件, 实现所需要的管理功能 这里以管理蜂鸣器为例进行开发 开发环境 : 代理站 :OS:linux arm-linux-gcc:3.4.1 net-snmp: SEP4020 arm7 管理站 :windows XP 自定义模块 get 与 set 实现 (1) 编写一个需要加入的 MIB 模块定义文件 :EM-LEDTEST-MIB.txt 编写 MIB 模块定义文件的语法, 由 SNMP 协议中 SMI 部分描述 SMI 所采用的是 ASN.1 的一个子集 具体的描述参见相应的 RFC 文档 MIB 模块定义文件如下 : EM-LEDTEST-MIB DEFINITIONS ::= BEGIN IMPORTS enterprises,object-type,integer32,counter32,timeticks FROM SNMPv2-SMI TEL: FAX: 技术社区 :

230 TEXTUAL-CONVENTION, RowStatus FROM SNMPv2-TC; ledtest OBJECT IDENTIFIER ::= { enterprises 100 ledvalue OBJECT-TYPE SYNTAX INTEGER MAX-ACCESS read-write STATUS current DESCRIPTION "This is a simple led test. It does nothing more than return its current value, and changes values only when set by an incoming SNMP set request." ::= { ledtest 1 ledvaluesincechanged OBJECT-TYPE SYNTAX TimeTicks UNITS "1/100th Seconds" MAX-ACCESS read-only STATUS current DESCRIPTION "This object indicates the number of 1/100th seconds since the ledvalue object has changed. If it is has never been modified, it will be the time passed since the start of the agent." ::= { ledtest 2 END 该 MIB 定义文件在 MIB 树 iso.org.dod.internet.private.enterprises 上定义了一个子树 ledtest, 该对象包含两个变量 ledvalue 和 ledvaluesincechanged 其中 ledvalue 为整数类型, 可读写 ledvaluesincechanged 为时间类型, 只读, 记录 ledvalue 变量自上次修改到现在的时间值 我们的目的是在代理程序中加入这个模块, 并能通过工具程序获得或设置变量的值 (2) 通过工具 mib2c 生成 C 代码 将上面的 MIB 定义文件拷贝到目录 /usr/local/share/snmp/mibs 下 然后, 以如下命令运行 mib2c 工具 : mib2c EM-LEDTEST-MIB.txt ledtest TEL: FAX: 技术社区 :

231 注意 :ledtest 为 MIB 文件中一个对象, 在当前目录下生成两个文件 :ledtest.h 和 ledtest.c (3) 对 ledtest.c 文件修改并增加读写功能, 修改文件如下 : /* * Note: this file originally auto-generated by mib2c using * : mib2c.old-api.conf :36:51Z hardaker $ */ #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> #include <net-snmp/agent/net-snmp-agent-includes.h> #include "ledtest.h" #include <stdio.h> //#include <sys/ioctl.h> /* * ledtest_variables_oid: * this is the top level oid that we want to register under. This * is essentially a prefix, with the suffix appearing in the * variable below. */ oid ledtest_variables_oid[] = { 1, 3, 6, 1, 4, 1, 100 ; static int ledvalue1 = 2; static time_t lastchanged = 0; /* * variable4 ledtest_variables: * this variable defines function callbacks and type return information * for the ledtest mib section */ struct variable2 ledtest_variables[] = { #define LEDVALUE 1 {LEDVALUE, ASN_INTEGER, RWRITE, var_ledtest, 1, {1, #define LEDVALUESINCECHANGED 2 {LEDVALUESINCECHANGED, ASN_TIMETICKS, RONLY, var_ledtest, 1, {2, TEL: FAX: 技术社区 :

232 ; void init_ledtest(void) { DEBUGMSGTL(("ledtest", "Initializing\n")); REGISTER_MIB("ledtest", ledtest_variables, variable2, ledtest_variables_oid); lastchanged = time(null); unsigned char *var_ledtest(struct variable *vp, oid * name, size_t *length, int exact, size_t *var_len, WriteMethod ** write_method) { static long long_ret; static int fd = 0; static int buff[1] = {0; if (header_generic(vp, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* * this is where we do the value assignments for the mib results. */ switch (vp->magic) { case LEDVALUE: fd = open("/dev/led",0); /* 打开设备 */ if(fd == -1) { printf("wrong\r\n"); exit(-1); printf("open is over\n"); TEL: FAX: 技术社区 :

233 read(fd,buff,1); /* 读取 led 设备的值 */ ledvalue1 = buff[0]; close(fd); /* 关闭设备 */ *write_method = write_ledvalue; return (u_char *) & ledvalue1; case LEDVALUESINCECHANGED: long_ret = (time(null) - lastchanged)*100; *var_len = sizeof(long_ret); return (unsigned char *) &long_ret; default: ERROR_MSG(""); return NULL; int write_ledvalue(int action, size_t name_len) { #define MAX_LEDVALUE 3 { static long static long static int fb = 0; u_char * var_val, u_char var_val_type, size_t var_val_len, u_char * statp, oid * name, intval; old_intval; fb = open("/dev/led",0); if(fb == -1) printf("test wrong\r\n"); exit(-1); printf("open is over\n"); TEL: FAX: 技术社区 :

234 switch (action) { case RESERVE1: if (var_val_type!= ASN_INTEGER) { fprintf(stderr, "write to ledtest not ASN_INTEGER\n"); return SNMP_ERR_WRONGTYPE; if (var_val_len > sizeof(long)) { fprintf(stderr, "write to ledtest: bad length\n"); return SNMP_ERR_WRONGLENGTH; intval = *((long *) var_val); if (intval > MAX_LEDVALUE ) { fprintf(stderr, "write to ledtest: bad value\n"); return SNMP_ERR_WRONGLENGTH; break; case RESERVE2: break; case FREE: break; case ACTION: old_intval = ledvalue1; ioctl(fb,intval,0); /* 对 led 设备进行设值 */ ledvalue1= intval; break; case UNDO: /* * Back out any changes made in the ACTION case */ ledvalue1 = old_intval ; break; case COMMIT: lastchanged = time(null); TEL: FAX: 技术社区 :

235 break; close(fb); return SNMP_ERR_NOERROR; (4) 交叉编译并安装 在 linux 环境下, 确保已下载 net-snmp, 并确保 arm-linux-gcc 安装成功并已 设置好环境变量 将 net-snmp 解压到根目录下, 先将修改好的两个文件, ledtest.h 和 ledtest.c, 拷贝到下载的 net-snmp 源代码目录下 agent/mibgroup 子目录中 进 入 net-snmp 源码目录下 ( 此处是 net-snmp , 以下使用该目录代表源码目录 ), 配置编译选项, 执行下列命令 :./configure --build=i686-linux --host=arm-linux CC=arm-linux-gcc --disable-ipv6 --with-endianness=little --disable-manuals --disable-ucd-snmp-compatibility --enable-as-needed --disable-embedded-perl --without-perl-modules --disable-snmptrapd-subagent --disable-applications --disable-scripts LDFLAGS="-static" --with-mib-modules="ledtest" 注意 : 各配置选项含义可以使用./configure help 来查看, 可以添加自己需要 的选项或者去掉不需要的选项, 其中的 LDFLAGS="-static" 将使最后生成的 snmpd 是静态的, 里面已经包含了库文件 ; 其中最后一项将 ledtest 加入到代理程 序中 配置完成后进行编译 :make 最后使用 make install 进行安装, 将会在 /usr/local/sbin 下生成 snmpd 可执行 文件 (5) 配置 snmpd.conf 文件 将源码下 EXAMPLE.conf.def 文件名修改为 snmpd.conf, 并做如下修改 # sec.name source community com2sec local localhost COMMUNITY com2sec mynetwork NETWORK/24 COMMUNITY 改为 : # sec.name source community com2sec local public com2sec local public TEL: FAX: 技术社区 :

236 com2sec mynetwork /24 public 其中 为管理端的 IP (6) 移植到目标开发板将 snmpd 和 snmpd.conf 文件移到 linux 的 nfs 下,snmpd 文件上传到 nfs/usr/local/sbin 目录下 ( 需要更改访问权限为可执行 ), 将 snmpd.conf 文件上传到 nfs/usr/local/share/snmp/ 下 ( 不存在的目录先要创建 ) trap 实现 trap 的实现我们仍然以蜂鸣器为例, 当蜂鸣器设置为 1( 即响 ) 时, 代理端发 trap 到管理端 ; 当蜂鸣器设置为 0( 即不响 ) 时,trap 的发送结束 为了简单起见, 使用了源码 net-snmp /agent/mibgroup/examples 下的 notification.c 和 notification.h, 修改 notification.c 如下 : #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> #include <net-snmp/agent/net-snmp-agent-includes.h> #include <stdio.h> #include "notification.h" void init_notification(void) { DEBUGMSGTL(("example_notification", "initializing(setting callback alarm)\n")); snmp_alarm_register(30, /* seconds */ SA_REPEAT, /* repeat (every 30 seconds). */ send_example_notification, /* our callback */ NULL /* no callback data needed */ ); void send_example_notification(unsigned int clientreg, void *clientarg) { /* * define the OID for the notification we're going to send * NET-SNMP-EXAMPLES-MIB::netSnmpExampleHeartbeatNotification */ TEL: FAX: 技术社区 :

237 oid notification_oid[] = { 1, 3, 6, 1, 4, 1, 8072, 2, 3, 0, 1 ; size_t notification_oid_len = OID_LENGTH(notification_oid); static u_long count = 0; static int fm = 0; static int buff[1] = {0; static int value = 0; oid objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 ; size_t objid_snmptrap_len = OID_LENGTH(objid_snmptrap); oid hbeat_rate_oid[] = { 1, 3, 6, 1, 4, 1, 8072, 2, 3, 2, 1, 0 ; size_t hbeat_rate_oid_len = OID_LENGTH(hbeat_rate_oid); oid hbeat_name_oid[] = { 1, 3, 6, 1, 4, 1, 8072, 2, 3, 2, 2, 0 ; size_t hbeat_name_oid_len = OID_LENGTH(hbeat_name_oid); oid ledvalue_oid[] = { 1, 3, 6, 1, 4, 1, 100,1, 0 ; size_t ledvalue_oid_len = OID_LENGTH(ledvalue_oid); netsnmp_variable_list *notification_vars = NULL; const char *heartbeat_name = "A girl named Maria"; #ifdef RANDOM_HEARTBEAT int heartbeat_rate = rand() % 60; #else int heartbeat_rate = 30; #endif int testledvalue = 1; DEBUGMSGTL(("example_notification", "defining the trap\n")); /* * add in the trap definition object */ snmp_varlist_add_variable(&notification_vars, /* * the snmptrapoid.0 variable */ objid_snmptrap, objid_snmptrap_len, TEL: FAX: 技术社区 :

238 /* * value type is an OID */ ASN_OBJECT_ID, /* * value contents is our notification OID */ (u_char *) notification_oid, snmp_varlist_add_variable(&notification_vars, /* * size in bytes = oid length * sizeof(oid) */ notification_oid_len * sizeof(oid)); hbeat_rate_oid, hbeat_rate_oid_len, ASN_INTEGER, (u_char *)&heartbeat_rate, snmp_varlist_add_variable(&notification_vars, /* sizeof(heartbeat_rate)); ledvalue_oid, ledvalue_oid_len, ASN_INTEGER, (u_char *)& testledvalue, sizeof( testledvalue)); * if we want to insert additional objects, we do it here */ if (heartbeat_rate < 30 ) { ++count; snmp_varlist_add_variable(&notification_vars, hbeat_name_oid, hbeat_name_oid_len, ASN_OCTET_STR, heartbeat_name, strlen(heartbeat_name)); DEBUGMSGTL(("example_notification", "sending trap %ld\n",count)); TEL: FAX: 技术社区 :

239 fm = open("/dev/led",0); if(fm == -1) { printf("wrong\r\n"); exit(-1); printf("open is over\n"); read(fm,buff,1); /* 读取 led 设备的值 */ value = buff[0]; close(fm); if(value==1) { send_v2trap(notification_vars); /* 当 led 设备的值为 1 时, 向管理站发送 trap*/ DEBUGMSGTL(("example_notification", "cleaning up\n")); snmp_free_varbind(notification_vars); 其中 snmp_alarm_register 中的参数是可以改变的 接下来交叉编译安装移植与上面介绍类似, 有以下两个改动 (1) 配置编译选项修改, 执行下列命令 :./configure --build=i686-linux --host=arm-linux CC=arm-linux-gcc --disable-ipv6 --with-endianness=little --disable-manuals --disable-ucd-snmp-compatibility --enable-as-needed --disable-embedded-perl --without-perl-modules --disable-snmptrapd-subagent --disable-applications --disable-scripts LDFLAGS="-static" --with-mib-modules="ledtest examples/notification " 这样可以将 ledtest 和 examples/notification 两个模块均加入到代理程序中 注意 : 在添加模块时, 可以一次添加几个模块, 只要在各个模块之间加空格就好 ; 而且自动加载的模块一定要一次性添加进去, 这样才会都实现 (2)snmpd.conf 配置文件中增加以下语句 : # send v1 traps trapsink :162 public TEL: FAX: 技术社区 :

240 # also send v2 traps trap2sink :162 secret # send traps on authentication failures authtrapenable 1 其作用是当有触发条件产生时, 代理端可以自动发送 trap 到管理端 关于 get set 以及 trap 的测试详见用户手册 在第二部分开发实现中, 我们都是以蜂鸣器为例, 实现了对 led 设备的管理 如果有其他的实际需要可以依照蜂鸣器的例子, 进行相应的修改操作 TEL: FAX: 技术社区 :

241 7.4 CGI 应用程序开发简介 CGI 的定义 CGI 全称是 公共网关接口 (Common Gateway Interface),HTTP 服务器与你的或其它机器上的程序进行 交谈 的一种工具, 其程序须运行在网络服务器上 Common Gate Interface 听起来让人有些专业, 我们就管它叫 CGI 好了 在物理上,CGI 是一段程序, 它运行在 Server 上, 提供同客户端 Html 页面的接口 这样说大概还不好理解 那么我们看一个实际例子 : 现在的个人主页上大部分都有一个留言本 留言本的工作是这样的 : 先由用户在客户端输入一些信息, 如名字之类的东西 接着用户按一下 留言 ( 到目前为止工作都在客户端 ), 浏览器把这些信息传送到服务器的 CGI 目录下特定的 cgi 程序中, 于是 cgi 程序在服务器上按照预定的方法进行处理 在本例中就是把用户提交的信息存入指定的文件中 然后 cgi 程序给客户端发送一个信息, 表示请求的任务已经结束 此时用户在浏览器里将看到 留言结束 的字样 整个过程结束 CGI 的功能 绝大多数的 CGI 程序被用来解释处理来自表单的输入信息, 并在服务器产生相应的处理, 或将相应的信息反馈给浏览器 CGI 程序使网页具有交互功能 CGI 的处理过程 ⑴ 通过 Internet 把用户请求送到服务器 ; ⑵ 服务器接收用户请求并交给 CGI 程序处理 ; ⑶ CGI 程序把处理结果传送给服务器 ; ⑷ 服务器把结果送回到用户 CGI 与 WebServer 信息传输与数据交换过程 CGI 有两种方法请求 Webserver 进行信息传输和数据交换 :GET 和 POST 1.POST 方法 TEL: FAX: 技术社区 :

242 (1) 服务器把它从标准输入接收到的客户机数据发送给 CGI 程序, 同时把 request_method 环境变量设置为 POST 而该 CGI 应用程序查询 request_method 环境变量, 以确保其处于 POST 数据的状态 (2)content_length 设置为输入数据量的字节数 ; (3)content_type 设置为客户端发送数据的类型 ; (4) 读取 HTML 表单中具体的数据, 即解码 URL 过程 ; (5) 信息处理 2.GET 方法 (1)request_method 设置为 GET, 而相应的 CGI 应用程序需要检查该环境变量以确保其处于接收 GET 数据状态 (2) 将服务器接收到的数据编码到环境变量 query_string( 有些服务器使用 path_info) (3)CGI 程序读取 query_string 环境变量内容确定的数据之后, 处理 HTML 表单中具体的数据 注 : 采用 GET 方法提交的 HTML 表单数据的时候, 客户机将把这些数据附加到由 action 标记命名的 URL 的末尾, 用一个? 把经过 URL 编码后的信息与 CGI 程序名字分开, 同时 GET 方法所能传输的数据有限 CGI 常用环境变量及分类 类型一 :Server-Specific 环境变量主要目的是描述与 CGI 程序所处的服务器有关的信息 gateway_interface: 指示服务器所支持的 CGI 接口的版本号, 其格式为 CGI/ 版本号 script_name : 调用 CGI 程序时所使用的文件名 如 /cgi-bin/hello.exe server_name :webserver 的主机名 别名或 ip 地址 server_port :server 接收请求时所使用的端口号, 并使用此端口监听 CGI 请求 注 : 可在 CGI 程序中使用 server_name 和 server_port 构成一个 URL, 指向驻留在 server 上的信息资源 server_port_secure : 接受 http 请求的服务器安全 加密端口 server_protocol : 用于发送请求的协议的名称和版本号, 一般为 HTTP/1.1 server_software : 调用 CGI 程序的 http 服务器的版本号, 一般为 HTTS/1.1 server_admin : 显示服务器网络管理员 TEL: FAX: 技术社区 :

243 类型二 :Request-Specific 环境变量主要目的是描述与用户的 CGI 请求相关联的有关信息 request_method:webserver 与 CGI 之间信息的传输方式, 分 GET 和 POST 两种 content_type: 指示所传输信息的 MIME( 通用 Internet 邮件扩充服务 ) 类型 一般为 application/x-www-form-urlencoded 表示来自于 HTML 表单 content_length:post 方式时, 从标准输入读到有效数据字节数, 必须使用 content_file: 采用 windows.httpd/wincgi 标准时, 包含了用于传送数据的文件名 query_string:get 方式时, 表示所传送的信息 path_info : 表示紧接着 CGI 程序名之后的其它路径信息, 常作为 CGI 程序参数 path_translated : 仅由部分服务器支持,CGI 程序的完整路径名 remote_host : 提供已分解的发请求客户的主机名 remote_ident : 如果服务器和客户支持 rfc931, 此变量将包含由远程用户的计算机提供的识别信息 auth_type: 若 webserver 支持保护 CGI 程序的验证机制, 此环境变量的值就是验证机制的类型 remote_user : 如果 auth_type 被设置, 此变量将包含用户提供并由服务器验证机制的用户名 注 :auth_type 和 remote_user 只有在用户被 server 成功地确认为合法用户后才被设置 类型三 :Client-Specific 环境变量主要目的是描述与请求 CGI 程序的客户机的有关信息 http_accept: 提供由逗号分开的并被客户机所支持的 MIME 类型清单 http_accept_encoding : 客户机能接受的编码形式 http_accept_language : 客户机能接受的语言类型 http_cookie : 客户机内的 cookie 内容 http_form : 使用者发出请求的电子邮件讯息 http_referer : 在读取 cgi 程式前, 客户端所指的 URL http_user_agent : 有关客户机浏览器的信息 TEL: FAX: 技术社区 :

244 7.4.6 CGI 编程实例 我们这里用 C 语言作为编程语言, 编写一个简单的控制 LED 的开和关的 CGI 程序 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #define DEVICE_NAME "/dev/sep4020_led" /* 驱动名字 */ #define LED_ON 1 /* 开启 led*/ #define LED_OFF 0 /* 关闭 led*/ int main() { int fd; int led; char *data; data = getenv("query_string");/* 这里我们只是用 Get 方式 */ printf("content-type:text/html\n\n"); printf("<title>led CGI TEST</title>\n"); printf("<body>\n"); printf("<h1>led CGI TEST</h1>\n"); fd=open(device_name,o_rdonly O_NONBLOCK);/* 打开 led 设备 */ if(fd < 0) printf("fd file failed\n"); else printf("fd = %d",fd); if(sscanf(data,"led=%d",&led)==1) { if(led == 1)ioctl(fd,LED_ON); /* 开启 led*/ else if(led == 0)ioctl(fd,LED_OFF); /* 关闭 led*/ else close(fd); exit(0); 好了, 程序编写完成, 我们保存为 led.c 接着进行编译 TEL: FAX: 技术社区 :

245 #arm-linux-gcc led.c o led.cgi 注意, 这里必须要编译成.cgi 后缀 由于, 我们这里要用到 led 的驱动, 所以在开启 webserver 之前还需要加载 led 的驱动, 如图 7.4 #mknod /dev/sep4020_led c /* 这里需要根据驱动的具体情况建立节点 */ #cd / #insmod sep4020_led.ko 7.5 图 7.4 最后开启 webserver, 我们就可以通过网页来控制开发板上的 led 灯了, 如图 图 7.5 TEL: FAX: 技术社区 :

246 在 PC 网页浏览器里调入 CGI 的 URL ( 一般是 就可以访问该 CGI 并且可以控制 LED 了, 如图 7.6 图 7.6 TEL: FAX: 技术社区 :

247 7.5 Sqlite 运行在 arm 上的简单介绍 PC 机编译安装 准备工作 : 1. 取得一个 arm-linux-gcc 的编译器 2. sqlite 的源码 sqlite tar.gz ( 本文以它为例 ) 3. 这里设 arm-linux-gcc 在 /usr/local/arm/3.4.1/arm-linux/bin/ 目录下 首先解压 sqlite tar.gz 到 /usr/local/arm/3.4.1/arm-linux 下 # cd /usr/local/arm/3.4.1/arm-linux # tar zxvf sqlite tar.gz -C /usr/local/arm/3.4.1/arm-linux( 可以直接在文件 浏览器中右击解压 ) # cd /usr/local/arm/3.4.1/arm-linux/sqlite 新建一个 sqlite-arm-linux 目录 # mkdir /usr/local/arm/3.4.1/arm-linux/sqlite-arm-linux # cd /usr/local/arm/3.4.1/arm-linux/sqlite-arm-linux #../sqlite-3.3.7/configure --prefix=/usr/local/arm/3.4.1/arm-linux/sqlite-arm-linux 编译并安装 #make #make install 理论上讲应该就没有问题了, 此时可以看到可执行文件 sqlite3 已经生成在 /usr/local/arm/3.4.1/arm-linux/sqlite-arm-linux/bin 目录下, 库文件已经生成在 /usr/local/arm.3.4.1/arm-linux/sqlite-arm-linux/lib 目录下 下面创建一个新的数据库文件名叫 "zieckey.db" ( 当然你可以使用不同的名字 ) 来测试数据库 直接输入 : /usr/local/arm/3.4.1/arm-linux/sqlite-arm-linux/bin/sqlite3 test.db 如果出现下面字样表明编译安装已经成功了. SQLite version Enter ".help" for instructions sqlite> 交叉编译 sqlite tar.gz 库文件 同上面的解压 sqlite tar.gz # tar zxvf sqlite tar.gz -C /usr/local/arm/3.4.1/arm-linux #cd /usr/local/arm/3.4.1/arm-linux/sqlite TEL: FAX: 技术社区 :

248 新建一个 sqlite-arm-linux 目录 # mkdir /usr/local/arm/3.4.1/arm-linux/sqlite-arm-linux # cd /usr/local/arm/3.4.1/arm-linux/sqlite-arm-linux 设置交叉编译环境 : # export PATH=/usr/local/arm/3.4.1/arm-linux/bin:$PATH #../sqlite-3.3.7/configure --host=arm-linux --prefix=/usr/local/arm-linux/sqlite-arm-linux 这部会出现下面的错误 : configure: error: unable to find a compiler for building build tools 这个错误的解决方法是 : 首先, 我们进入目录 usr/local/arm-linux/sqlite-1.3.7, 打开其中的 configure 文件, 用查找功能找到下列语句 : #else # test "$cross_compiling" = yes && # { { echo "$as_me:13264: error: cannot check for file existence when cross compiling" >&5 #echo "$as_me: error: cannot check for file existence when cross compiling" >&2; # { (exit 1); exit 1; ; 把其中的 { (exit 1); exit 1; ; 改为 { (echo 1); echo 1; ; 一共有三处, 分别在 19261,20420,20446 行, 都改过来 然后, 我们要设置 config_target_cc 和 config_build_cc 两个环境变量 config_target_cc 是交叉编译器,config_BUILD_CC 是主机编译器 重来 : #export config_build_cc=gcc #export config_target_cc=arm-linux-gcc 下面重新编译就可以了 #../sqlite-3.3.7/configure --host=arm-linux --prefix=/usr/local/arm/3.4.1/arm-linux/sqlite-arm-linux 然后我们会发现在在 /usr/local/arm/3.4.1/arm-linux/sqlite-arm-linux 目录下生成一些相关文件 : config.log config.status libtool Makefile sqlite3.pc 下面在 make 之前我们修改一下 Makefile 文件, 把其中的 BCC = arm-linux-gcc -g -O2 为 BCC = gcc -g -O2( 若没有这样一句话, 只存在 BCC = arm-linux-gcc g 这个语句, 只要在其后加上 O2 就可以了, 注意的是大写的 O) #make #make install 注明 : "# make install" 这一步将会在 /usr/local/arm/3.4.1/arm-linux/sqlite-arm-linux/lib 生成库文件 # cd lib # file libsqlite3.so 会出现这样的话语 : libsqlite3.so.0.8.6: ELF 32-bit LSB shared object, ARM, version 1 (ARM), not stripped TEL: FAX: 技术社区 :

249 此时生成的 sqlite 文件是还未 strip 过的, 你可以使用命令 file sqlite 查看文件信息 用 strip 处理过后, 将去掉其中的调试信息, 执行文件大小也将小很多 命令如下 : # arm-linux-strip libsqlite3.so 这样我们已经编译出了 在 ARM 板上运行 sqlite 将 /usr/local/arm/3.4.1/arm-linux/sqlite-arm-linux/bin/ 目录下的 sqlite3 文件下 载到你的 arm 板上, 方法很多, 你需要根据自己的情况来选择 如 ftp,nfs, 串口 等 # chmod +wx sqlite3 [root@51board var]#./sqlite3 zieckey.db./sqlite3: error while loading shared libraries: libsqlite3.so.0: cannot open shared object file: No such file or directory 这里是因为刚刚编译时编译的是动态连接库形式的, 所有我们还要将库文件 下载到 ARM 板上 将 /usr/local/arm/3.4.1/arm-linux/sqlite-arm-linux/lib 目录下所有文件下到 ARM 板上 再次运行, [root@51board var]#./sqlite3 zieckey.db./sqlite3: error while loading shared libraries: libsqlite3.so.0: cannot open shared object file: No such file or directory 还是出错, 哦, 我们没有设置环境变量, 把库文件下到 ARM 板上的 /lib/ 目录下, 这里设置环境就像下面 : [root@51board var]# export LD_LIBRARY_PATH=/lib:$LD_LIBRARY_PATH 1. 执行 sqlite3 demo.db, 执行结果 ( 如图 7.7) 所示 TEL: FAX: 技术社区 :

250 图 此时, 我们执行.tables, 没有输出, 因为现在我们还没有建表 3. 我们下面演示下用 SQL 语句建立一张表 输入 create table funny(name varchar(10),age smallint); ( 如图 7.8) 图 我们现在可以执行.tables, 就会看到我们刚才创建的表 ( 如图 7.9) TEL: FAX: 技术社区 :

251 图 我们向刚创建的 funny 表中添加数据, 使用命令 insert into funny values("gmc",23); ( 如图 7.10) 图 可以使用命令 select * from funny;, 来查看表中的数据 ( 如图 7.11) 我们会发现刚才插入的数据显示出来了 TEL: FAX: 技术社区 :

252 图 执行.quit, 退出 SQLite( 图 7.12) 图 如何在 Linux 下用 C/C++ 语言操作数据库 sqlite3 接下来主要讲述如何在 C/C++ 语言中调用 sqlite 的函数接口来实现对数据 TEL: FAX: 技术社区 :

253 库的管理 说明 我们刚刚已经编译好了 sqlite 的库文件 :libsqlite3.a libsqlite3.la libsqlite3.so libsqlite3.so.0 libsqlite3.so pkgconfig 和可执行文件 sqlite3 我们的 sqlite3 的安装目录在 /usr/local/arm-linux/sqlite-arm-linux/ 目录下 为了操作简便, 将你的安装文件复制到 /usr/local/sqlite3 这个目录, 这样我们好在下面的操作中更加统一, 从而减少出错的概率 例如 : [root@localhost home]# cp -rf /usr/local/arm-linux/sqlite-arm-linux/ /usr/local/sqlite3 这里 /usr/local/arm-linux/sqlite-arm-linux/ 是你的安装目录, 也就是说你的 sqlite 原来就是安装在这里, 这样之后, 我们的 sqlite3 的库文件目录是 : /usr/local/sqlite3/lib 可执行文件 sqlite3 的目录是 : /usr/local/sqlite3/bin 头文件 sqlite3.h 的目录是 : /usr/local/sqlite3/include 现在开始我们的 Linux 下 sqlite3 编程之旅 开始 这里我们现在进行一个测试 现在我们来写个 C 程序, 调用 sqlite 的 API 接口函数 下面是一个 C 程序的例子, 显示怎么使用 sqlite 的 C/C++ 接口 数据库的名字由第一个参数取得且第二个参数或更多的参数是 SQL 执行语句 这个函数调用 sqlite3_open() 在 16 行打开数据库, 并且 sqlite3_close() 在 25 行关闭数据库连接 [root@localhost temp]# vi opendbsqlite.c 按下 i 键切换到输入模式, 输入下列代码 : // name: opendbsqlite.c // This prog is used to test C+ API for sqlite3.it is very simple // Author : zieckey All rights reserved. // data : 2006/11/13 #include <stdio.h> #include <sqlite3.h> TEL: FAX: 技术社区 :

254 int main( void ) { sqlite3 *db=null; char *zerrmsg = 0; int rc; // 打开指定的数据库文件, 如果不存在将创建一个同名的数据库文件 rc = sqlite3_open("zieckey.db", &db); if( rc ) { fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); exit(1); else printf("you have opened a sqlite3 database named zieckey.db successfully!\ncongratulations! Have fun! ^-^ \n"); sqlite3_close(db); // 关闭数据库 return 0; 退出, 保存 ( 代码输入完成后, 按下 Esc 键, 然后输入 : :wq, 回车就好拉, 也可以直接打开文件修改保存 ) 现在编译 : [root@localhost temp]# gcc opendbsqlite.c -o db.out 或者遇到这样的问题 : [root@localhost temp]# gcc opendbsqlite.c -o db.out opendbsqlite.c:11:21: sqlite3.h: 没有那个文件或目录 opendbsqlite.c: In function `main': opendbsqlite.c:19: `sqlite3' undeclared (first use in this function) opendbsqlite.c:19: (Each undeclared identifier is reported only once opendbsqlite.c:19: for each function it appears in.) opendbsqlite.c:19: `db' undeclared (first use in this function) 这是由于没有找到头文件的原因 也许会碰到类似这样的问题 : [root@localhost temp]# gcc opendbsqlite.c -o db.out TEL: FAX: 技术社区 :

255 /tmp/cctkitnn.o(.text+0x2b): In function `main': : undefined reference to `sqlite3_open' /tmp/cctkitnn.o(.text+0x45): In function `main': : undefined reference to `sqlite3_errmsg' /tmp/cctkitnn.o(.text+0x67): In function `main': : undefined reference to `sqlite3_close' /tmp/cctkitnn.o(.text+0x8f): In function `main': : undefined reference to `sqlite3_close' collect2: ld returned 1 exit status 这是个没有找到库文件的问题 下面我们着手解决这些问题 由于用到了用户自己的库文件, 所用应该指明所用到的库, 我们可以这样编译 : [root@localhost temp]# gcc opendbsqlite.c -o db.out -lsqlite3 我用用 -lsqlite3 选项就可以了 ( 前面我们生成的库文件是 libsqlite3.so 等, 去掉前面的 lib 和后面的版本标志, 就剩下 sqlite3 了所以是 -lsqlite3 ) 如果我们在编译安装的时候, 选择了安装路径, 例如这样的话 :... #../sqlite/configure --prefix=/usr/local/sqlite3 # make... 这样编译安装时,sqlite 的库文件将会生成在 /usr/local/sqlite3/lib 目录下 sqlite 的头文件将会生成在 /usr/local/sqlite3/include 目录下, 这时编译还要指定库文件路径, 因为系统默认的路径没有包含 /usr/local/sqlite3/lib [root@localhost temp]# gcc opendbsqlite.c -o db.out -lsqlite3 -L/usr/local/sqlite3/lib 如果还不行的话, 可能还需要指定头文件 sqlite3.h 的路径, 如下 : [root@localhost temp]# gcc opendbsqlite.c -o db.out -lsqlite3 -L/usr/local/sqlite3/lib -I/usr/local/sqlite3/include 这样编译应该就可以了, 运行 : TEL: FAX: 技术社区 :

256 temp]#./db.out./db.out: error while loading shared libraries: libsqlite3.so.0: cannot open shared object file: No such file or directory 运行也许会出现类似上面的错误 这个问题因为刚刚编译的时候没有选择静态编译, 那么按照默认的编译就动态编译的, 动态编译后, 由于可执行文件在运行时要调用系统库文件, 那么沿着系统默认的库文件搜索路径搜索, 就可能找不到我们现在所需的库文件 致使出现 "error while loading shared libraries" 等错误 我们可以这样解决 : 方法一 : 静态编译在编译时加上 -static 参数, 例如 : [root@localhost temp]# gcc opendbsqlite.c -o db.out -lsqlite3 -L/usr/local/sqlite3/lib -I/usr/local/sqlite3/include -static [root@localhost temp]# ll 总用量 rwxr-xr-x 1 root root 月 13 10:50 db.out -rw-r--r-- 1 root root 月 13 10:31 opendbsqlite.c 可以看到输出文件 db.out, 其大小为 : k 运行, 好了, 没有出现错误 [root@localhost temp]#./db.out You have opened a sqlite3 database named zieckey.db successfully! Congratulations! Have fun! ^-^ 方法二 : 重新配置系统环境变量 LD_LIBRARY_PATH 这时需要指定 libsqlite3.so.0 库文件的路径, 也就是配置系统环境变量 LD_LIBRARY_PATH, 使系统能够找到 libsqlite3.so.0 去掉 static, 再编译 : [root@localhost temp]# gcc opendbsqlite.c -o db.out -lsqlite3 -L/usr/local/sqlite3/lib -I/usr/local/sqlite3/include [root@localhost temp]# ll 总用量 36 -rwxr-xr-x 1 root root 月 13 10:56 db.out -rw-r--r-- 1 root root 月 13 10:31 opendbsqlite.c [root@localhost temp]# 可以看到输出文件 db.out, 其大小为 12716k, 比刚才的静态编译要小得多 所以我们推荐使用动态编译的方法 好了, 现在我们来指定系统环境变量 TEL: FAX: 技术社区 :

257 LD_LIBRARY_PATH 的值在 shell 下输入 : [root@localhost temp]# export LD_LIBRARY_PATH=/usr/local/sqlite3/lib:$LD_LIBRARY_PATH 再运行 [root@localhost temp]#./db.out You have opened a sqlite3 database named zieckey.db successfully! Congratulations! Have fun! ^-^ 这样就打开了数据库, 操作成功 TEL: FAX: 技术社区 :

258 7.6 GPRS 程序开发简介 简介 首先是 gprs 的硬件,prochip 做的这个 gprs 模块采用 sim300, 封装好了之后对用户而言就是一个 8 引脚的接口 其接口从上到下分别是 vcc rxd txd pwrkey en dtr dcd 以及 gnd 如( 图 6.29) 所示 对于 txd 和 rxd 引脚, 就是用 txd 连接板子的 rxd,rxd 连板子的 txd En 是电源使能, 也就是使能模块的 4.2v 电压, 模块在工作期间, 该引脚必须置成高电平, 当该引脚为低电平的时, 模块电源断电, 因此, 该引脚也能作为模块的 reset Pwrkey 是特别值得注意的, 实际上, 对 sim300 的启动并不只是将 pwrkey 简单的置高或者置地那么简单, 从 datasheet 了解到, 必须先置高大于 2s, 再置低之后, 才能正确启动模块 Dtr 以及 cdc 起到模块与板子相互控制的作用 对于 sim300 模块而言,dtr 是输入端口,dcd 是输出端口 Dtr 引脚表示数据终端准备好 (data terminal is ready), 当 mcu 发送出 at+csclk=1 命令后, 然后 dtr 置高, 模块进入睡眠状态 ; 从睡眠中将模块唤醒, 只要 dtr 置低即可 另外, 要从 transport mode 进入 at command mode 的时候, 可将 dtr 置低 Dcd 表示数据载波探测 ( data carrier detection) 其默认是高电平 在 transport mode 下 tcp/udp 连接完成时,dcd 为低电平 ; 当 windows ppp dialing well 时,dcd 为低电平 但在 at command mode 下, 这两个引脚即使闲置,sim300 模块也能与板子进行通信 图 7.13 TEL: FAX: 技术社区 :

259 7.6.2 串口设置 接着是串口设置,sim300 模块在启动后的默认波特率是 , 如不用指令 at+ipr=### 的话, 那模块就是默认波特率, 上位机也必须使用 的波特率才能与 sim300 模块正常通信 若想使用其他的波特率, 比如 19200, 那么必须在模块启动之后先设置上位机的波特率为 , 然后向模块发送 at+ipr=19200 设置模块的波特率为 19200, 再将上位机的波特率设置为 19200, 这样才能实现上位机以 的波特率与 sim300 模块实现通信 下面介绍 sim300 模块在 pc 控制下的使用方法 (1) 将 pc 串口转为 TTL3.3v 电压, 并将 pc 的 txd rxd 与模块的 rxd txd 正确连接 (2) 将 sim300 模块的天线连接好 ( 天线一定要连接 ) (3) 模块的 vcc 接 5v 电压 gnd 接地 en 接高电平 dtr 和 dcd 闲置不用 (4) 将 pwrkey 置为高电平大于 3s, 当看到 sim300 上的 led 灯 DS6 有规律的闪动后, 说明模块启动成功, 然后再将 pwrkey 置低 (5) 打开串口调试助手并且正确设置之后, 向 sim300 模块发送命令 at( 命令之后要跟换行符 ), 当模块回送 ok 之后, 说明模块正常工作 如 ( 图 图 7.15) 所示 图 7.14 TEL: FAX: 技术社区 :

260 图 Sim300 模块简易 at 指令说明 波特率设置 发送 AT+IPR=? 可以查看模块所支持的波特率 ; 发送 AT+IPR? 查看模块当前的波特率, 若为 0, 则是默认的波特率 ; 发送 AT+IPR=###, 比如 9600 可以将模块设置成所需要的波特率 ; 更改完模块的波特率之后, 必须也相应更改上位机的波特率, 否则两者之间将无法通信 ( 如图 7.16) TEL: FAX: 技术社区 :

261 图 一些常用的 at 命令发送 AT, ATI, AT+CSQ, AT+CREG?, AT+CGATT? 分别用于查看模块是否正常工作 模块的厂商信息 信号强度 网络信号注册 模块是否已经连上 gprs( 如图 7.17) 这些, 在 sim300 模块的详细 at 指令手册中都有说明 图 7.17 TEL: FAX: 技术社区 :

262 拨打电话 发送 ATD138########; 即表示拨打 138######## 这个号码, 注意! 这个命令的末尾一定要加分号! 否则即是错误!( 如图 7.18) 图 发送英文短信 发送 AT+CMGF=1 返回 OK 发送 AT+CSCS= GSM 返回 OK 发送 AT+CMGS= 返回 > 发送 hello,gprs! 返回 > TEL: FAX: 技术社区 :

263 注意 : 在这个地方, 必须在每条短信的结尾再发送 ctrl z, 即二进制下的字符 0x1a, 以此表示这条短信的结尾, 若短信后不加这个字符, 短信将无法发送返回, +CMGS: 15 表示短信发送完成 ( 如图 7.19) 图 7.19 当然, 在这种方式下只能发送英文短信, 参考 sim300 模块手册, 还有发送 中文短信方式 在 at command 模式下连接 tcp 发送 at+cipmode? 查看模块工作在何种模式下发送 at+cipmode=0 将模块设置为 at command 模式发送 at+cipstart= TCP, , 80 连接 Google 返回 connect ok 发送 at+cipsend TEL: FAX: 技术社区 :

264 返回 > 发送需要发送的信息, 注意, 要在信息后加 ctrl z, 即 hex 码 0x1a 返回 send 0k, 即表示发送成功, 可以看到返回的信息 ( 如图 7.20) 图 7.20 当然,sim300 连接 tcp 有多种方式, 至于其他几种方式可查看手册 Linux 下应用程序参考 Sim300 模块是一个基于串口操作的应用, 其 linux 下的应用程序所需要做的主要就是对串口的读写操作, 即对串口驱动 read 和 write 函数的调用 使用 read 函数要注意阻塞后程序停止不动, 所以要用 select 进行控制, 注意 tv 每次循环都要设置 ;write 不用考虑阻塞, 但要用循环写方式保证一定写完, 其实读最好也用循环读方式保证一定能读到所有东西并且能拼接在一起, 然后再进行 TEL: FAX: 技术社区 :

265 其他操作 在实际编程中, 对串口的写直接用 write 函数即可 ; 而对串口的读需要设置超时时间, 即在超时时间内读取串口数据 若串口回送信息时间小于超时时间, 则可以正确读取串口发送的信息, 若串口回送信息时间大于超时时间, 则未读取的信息将在下一次的 read 调用中被读取 Linux 下的串口读写实现后, 对 gprs 的控制也就不难了,sim300 模块的 en pwrkey 引脚可以用 gpio 口来控制 用 write 函数发送 at 命令, 用 read 读取回送信息, 当然, 在调试时要能把握好回送信息的延时时间 7.7 CDMA 程序开发 硬件说明 Prochip 的 cdma 模块采用的是东大通信公司的 eden800 模块, 该 cdma 模块引出了 7 个引脚, 分别是 vcc rxd txd reset dtr ext 以及 gnd 其中, dtr 和 ext 未用, 因此, 本 cdma 模块实际上只引出了 5 个引脚, 而控制引脚只有一个, 即 reset 对于 txd 和 rxd, 可以参考 gprs 模块的使用一节 而 reset 引脚是该模块的重置功能, 对其置高电平大于 3s 后, 模块将复位 模块的引脚如 ( 图 7.21) 所示 图 7.21 TEL: FAX: 技术社区 :

266 7.7.2 串口设置 接着是串口设置,eden800 模块在启动后的默认波特率是 , 如不用指令 at+ipr=### 的话, 那模块就是默认波特率, 上位机也必须使用 的波特率才能与 eden800 模块正常通信 若想使用其他的波特率, 比如 19200, 那么必须在模块启动之后先设置上位机的波特率为 , 然后向模块发送 at+ipr=19200 设置模块的波特率为 19200, 再将上位机的波特率设置为 19200, 这样才能实现上位机以 的波特率与 eden800 模块实现通信 下面介绍 sim300 模块在 pc 控制下的使用方法 (1) 将 pc 串口转为 TTL3.3v 电压, 并将 pc 的 txd rxd 与模块的 rxd txd 正确连接 (2) 将 eden800 模块的天线连接好 ( 天线一定要连接 ) (3) 模块的 vcc 接 5v 电压 (4) 打开串口调试助手并且正确设置之后, 向 eden 模块发送命令 at( 命令之后要跟换行符 ), 当模块回送 ok 之后, 说明模块正常工作 如 ( 图 7.22) 所示 图 7.22 TEL: FAX: 技术社区 :

267 7.7.3 eden800 模块简易 at 指令说明 设置模块速率 AT+IPR=<speed> 功能 : 设定模块的波特率语法 :AT+IPR=<speed> <speed>: 为波特率, 取值范围 1200bps bps 结果 : 返回 OK 命令 : 查询命令为 AT+IPR?; 查询支持范围值命令 AT+IPR=?; 示例 1:AT+IPR? +IPR: 9600 OK 示例 2:AT+IPR=? +IPR: ( ), (45, 50, 75, 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, , ) Ok 示例 3:AT+IPR= OK 图 7.23 TEL: FAX: 技术社区 :

268 控制回显 ATEx 功能 : 控制字符是否回显语法 :ATEx x = 0 不回显 x = 1 回显结果 : 返回 OK 示例 :ATE0 OK 图 语音呼叫 AT+CDV<number> 功能 : 拨打语音电话 语法 :AT+CDV<number> TEL: FAX: 技术社区 :

269 <number> 为呼出时目的号码结果 :VOICE CALL : BEGIN OK 示例 :AT+CDV10010 VOICE CALL : BEGIN OK 注意 : 若模块有来电时发送该命令则返回 ERROR 图 tcp 连接 基于 at 命令的发送方式拨号连接 AT+TCPD 返回信息 :$CONNECT 打开 SOCKET: ( 假设服务器 IP 为 DA , 通行端口为 2000) AT+TCPOPEN= ,2000 返回信息 :$TCPOPEN 传送数据 : ( 要传送的数据为 hi) AT+TCPDATA=2( 回车 ) TEL: FAX: 技术社区 :

270 OK( 回显信息 ) Hi 返回信息 :$TCPSENDDONE 接收数据 : ( 服务器发送了数据 re) 返回信息 :$ TCPRCVDATA: 2( 总共占 3 位, 数据最长 240 个字节 )re 关闭 SOCKET: AT+TCPCLOSE 返回信息 :$TCPCLOSED 关闭连接 : AT+TCPEXIT 返回信息 :$NETEXITED API 接口说明 在 CDMA 模块中, 硬件复位用到了通用 GPIO 驱动, 所以在使用之前请加载 sep4020_gpio.ko, 驱动位于 /linux/drivers/char/sep4020_char/sep4020_gpio.c CDMA 模块中提供了很多 API 接口 : 1. void set_speed(int fd, int speed) 用于设置串口通信的波特率, 所以在设置时要保证通信主机端和开发板端的波特率一致 2. int set_raw_mode(int fd) 用于设置串口的工作模式, 返回 0 设置成功,-1 则表示设置失败 3. void hardware_reset(int gpio_fd) 用于硬件复位, 在允许程序时要保证 sep4020_gpio.ko( 或者被编译进内核 ) 已经加载 4. int make_call(int fd,char *telphone_num) 用于拨打电话,fd 为串口的文件描述符,telphone_num 为所拨打的电话号码, 注意是字符串的形式 注意这儿拨打电话不管是否成功, 模块都返回 OK, 模块只负责将号码拨出, 不具有检测号码是否有效的功能, 具体用法见 demo 5. int hang_up(int fd ) 挂断电话, 返回 0 表示成功挂断,-1 为操作失败 6. 下面是关于 TCP 的一些 API 函数, 在调用这些函数之前请仔细阅读手册 SOCKET 接口说明, 了解 TCP 操作的流程, 按照 TCP 操作流程提供了 5 个函数, 分别为 : int tcp_connect(int fd) int tcp_open (int fd,char* ip_string,const char* port) int tcp_send(int fd,char *send_message) int tcp_close(int fd) int tcp_exit(int fd) 7. int tcp_connect(int fd) 用于建立拨号连接,fd 为串口的文件描述符 0 表示连接成功,-1 表示操作失败 8. int tcp_open (int fd,char* ip_string,const char* port) 用于指定的端口的 TCP 连 TEL: FAX: 技术社区 :

271 接,ip_string 为端口 IP,port 为端口 port 号 0 表示连接成功,-1 表示操作失败 9. int tcp_send(int fd,char *send_message) 通过 TCP 连接发送数据, 由于各个网站类型的不同, 有些网站在你发出请求后会自动断开连接, 具体应用见 demo, 请输入符合 HTTP 协议的合法指令 10. int tcp_close(int fd) 用于断开指定端口的连接,0 表示操作成功,-1 表示操作失败 11. int tcp_exit(int fd) 用于断开拨号连接,0 表示操作成功,-1 表示操作失败 Linux 下应用程序参考 Eden800 模块是一个基于串口操作的应用, 其 linux 下的应用程序所需要做 的主要就是对串口的读写操作, 即对串口驱动 read 和 write 函数的调用 使用 read 函数要注意阻塞后程序停止不动, 所以要用 select 进行控制, 注意 tv 每次循环 都要设置 ;write 不用考虑阻塞, 但要用循环写方式保证一定写完, 其实读最好 也用循环读方式保证一定能读到所有东西并且能拼接在一起, 然后再进行其他操 作 在实际编程中, 对串口的写直接用 write 函数即可 ; 而对串口的读需要设置 超时时间, 即在超时时间内读取串口数据 若串口回送信息时间小于超时时间, 则可以正确读取串口发送的信息, 若串口回送信息时间大于超时时间, 则未读取 的信息将在下一次的 read 调用中被读取 Linux 下的串口读写实现后, 对 gprs 的控制也就不难了,eden800 模块的 reset 引脚可以用 gpio 口来控制 用 write 函数发送 at 命令, 用 read 读取回送信息, 当然, 在调试时要能把握好回送信息的延时时间 CDMA 实例 : #include <stdio.h> /* 标准输入输出定义 */ #include <stdlib.h> /* 标准函数库定义 */ #include <unistd.h> /*Unix 标准函数定义 */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> /* 文件控制定义 */ #include <termios.h> /*PPSIX 终端控制定义 */ #include <errno.h> /* 错误号定义 */ #include <memory.h> #include "eden_800.h" int main(int argc, char **argv){ int status; int fd; int fd_gpio; TEL: FAX: 技术社区 :

272 int i,j; char tel_num[] = " "; char *send_message="get /test/test.txt HTTP/1.1\r\n\nHOST: // 注意这儿的命令要符合 HTTP 协议 fd= open("/dev/ttys1",o_rdwr); if (fd == -1) { perror("can't Open Serial Port1 \n"); exit(-1); printf("open serial port1 \n"); fd_gpio = open("/dev/sep4020_gpio",o_rdwr); if(fd_gpio == -1) { perror("can't open sep4020_gpio\n"); exit(-1); printf("open sep4020_gpio\n"); status=test(fd); //test(fd) 用来测试模块的情况 if(status == TEST_BAD) { hardware_reset(fd_gpio); set_speed(fd,115200); set_raw_mode(fd); status=tcp_connect(fd); tcp_open(fd,"ca.5b.f8.73","80");// status = tcp_send(fd,send_message); // 根据访问不同的网站的回应来进一步运行程序 switch(status) { case TCP_SEND_FAIL: { exit(-1); case TCP_SEND_OK: { printf("go to out2\n"); tcp_recieve(fd); tcp_close(fd); tcp_exit(fd); TEL: FAX: 技术社区 :

273 break; case TCP_RECIEVE_OK: { printf("go to out1\n"); tcp_close(fd); tcp_exit(fd); break; case TCP_CLOSE_OK: { printf("go to out\n"); tcp_exit(fd); break; default:break; while(1); close(fd); close(fd_gpio); return 0; TEL: FAX: 技术社区 :

274 7.8 HDLC 模块 HDLC 简介 HDLC 是一种面向比特的数据链路控制协议 HDLC 的全称是高级数据链路控制协议 (High Level Data Link Control), 它是国际标准化组织 (ISO) 根据 IBM 公司的 SDLC(Synchronous Data Link Control) 协议扩展开发而成的 HDLC 具有如下特点 : 1 协议不依赖于任何一种字符编码集 ; 2 数据报文可透明传输, 用于透明传输的 0 比特插入法 易于硬件实现 ; 3 全双工通讯, 不必等待确认可连续发送数据, 有较高的数据链路传输效率 ; 4 所有帧均采用 CRC 校验, 对信息帧进行顺序编号, 可防止漏收或重收, 传输可靠性高 ; 5 传输控制功能与处理功能分离, 具有较大的灵活性和较完善的控制功能 由于以上特点, 目前网络设计及整机内部通讯设计普遍使用 HDLC 数据链路控制协议 7.82 HDLC 中常用的操作方式 (1) 正常响应方式 NRM 正常响应方式 NRM(Normal Response Mode) 一种非平衡数据链路操作方式, 有时也称为非平衡正常响应方式 该操作方式使用于面向终端的点到点或一点到多点的链路 在这种操作方式下, 传输过程由主节点启动, 从节点只有收到主节点某个命令帧后, 才能作为响应向主节点传输信息 响应信息可以由一个或多个帧组成, 若信息由多个帧组成, 则应指出哪一帧是最后一帧 主节点负责管理整个链路, 且具有轮询 选择从节点及向从节点发送命令的权利, 同时也负责对超时 重发及各类恢复操作的控制 (2) 异步响应方式 ARM 异步响应方式 ARM(Asynchronous Response Mode) 也是一种非平衡数据链路操作方式, 与 NRM 不同的是,ARM 下的传输过程由从节点启动 从节点主动发送给主节点的一个或一组帧中可包含有信息, 也可以是仅以控制为目的而发的帧 在这种操作方式下, 由从节点来控制超时和重发 该方式对采用轮询方式的多节点链路来说是必不可少的 (3) 异步平衡方式 ABM 异步平衡方式 ABM(Asynchronous Balanced Mode) 是一种允许任何节点来启动传输的操作方式 为了提高链路传输效率, 节点之间在两个方向上都需要有较高的信息传输量 在这种操作方式下, 任何时候任何节点都能启动传输操作, 每个节点点即可以作为主节点又可以作为从节点, 即每个节点都是组合节点 各个节点都有相同的一组协议, 任何节点都可以发送或接受命令, 也可以给出应答, 并且各节点对差错恢复过程都负有相同的责任 TEL: FAX: 技术社区 :

275 7.8.3 HDLC 模块硬件介绍 我们的 HDLC 使用的是 SI2404, 在具体的实现中, 我们具体使用该芯片的 RESET 管脚, 通过 PG11 口进行控制, 这一部分将在驱动中具体实现,5,6 两个管脚为具体的数据发送与传输脚, 我们是通过串口进行发送和接收的, 直接在应用程序中即可以使用 下面是具体的硬件原理图 : 图 7.26 接着我们来看一下我们应用程序的具体实现流程 ; TEL: FAX: 技术社区 :

276 芯片的 RESET SI2404 的初始化 AT 命令进行初始化 AT 命令进行拨号 打包所要传输的数据 数据传输模式 根据拨号返回命令开始传输 解析返回数据包 接收失败 重新发送失败的包 图 7.27 首先我们通过驱动的调用来实现芯片的 RESET, 然后使用串口发送 AT 命令 进行初始化 在芯片初始化完毕后, 我们通过拨号进行连接, 成功连接后, 将返 回连接成功信息, 并进入数据传输状态, 这时我们就可以发送开始打包的数据, 在具体的实现中, 我们通过网控器连接到 PC 串口上, 这样就可以在串口调试助 手中显示出所传输的数据, 当然其中包括了串口传输的头和尾 由于应用程序过大, 在这我们将不再列出其中的源码, 应用程序的使用方法如 下 : 首先, 确认 SW1101 拨到 on 上面,J1201 跳线帽插上 然后创建节点号, 具体命令如下 : cd /dev mknod hdlc c insmod sep4020_hdlc.ko 最后就可以运行应用程序了./test TEL: FAX: 技术社区 :

277 7.9 PSAM 应用说明 PSAM 卡在金融领域中有着广泛的应用, 主要用于商户 POS 机 网点终端 直联终端等端末设备上 PSAM 卡负责机具的安全控管, 支持 PIN 检验 KEY 认证 数据加密 解密 MAC 验证 同时,PSAM 卡还具有 IC 卡相同的电子存折和电子钱包的功能 因此,PSAM 卡具有一定的通用性, 经过个人化处理的 PSAM 卡能在不同的机具上 PSAM 卡支持多级发卡的机制, 各级发卡方在卡片主控密钥和应用主控密钥的控制下创建文件和装载密钥 文件结构 SMARTCOS-PSAM 的文件系统是完全遵照 中国金融集成电路 IC 卡规范及应用规范 PSAM 卡应用规范 和 ISO/IEC 来组织的, 具体的层次结构如下图所示 : 图 主控文件 (Master File,MF) 主控文件是整个文件系统的根 ( 可看做根目录 ), 每张卡有且只有一个主控文件 它是在卡的个人化过程中首先被建立起来的, 在卡的整个生命周期内一直存在并保持有效, 可存储卡的公共数据信息并为各种应用服务 由个人化建立起来的主控文件包括文件控制参数以及文件安全属性等信息 在物理上, 主控文件占有的存储空间包括 MF 文件头的大小以及 MF 所管理的 EF 和 DF 的所有存储空间 TEL: FAX: 技术社区 :

278 专用文件 (Dedicated File,DF) 在 MF 下针对不同的应用建立起来的一种文件, 是位于 MF 之下的含有 EF 的一种文件结构 ( 可看做文件目录 ), 它存储了某个应用的全部数据以及与应用操作相关的安全数据 DF 由创立文件命令建立 它的大小在建立后被确定, 此后不能更改 对 DF 的建立操作由 MF 的安全属性控制 在 DF 下面不可再建立子 DF, 只能建立 EF 为了保证各个 DF 的相互独立, 只能从文件系统的 MF 层次选择一个 DF, 对 DF 下的数据进行的操作由各当前系统的状态机控制 基本文件 (Elementary File,EF) 基本文件存储了各种应用的数据和管理信息, 它存在于 MF 和 DF 下 EF 从存储内容上分为两类 : 安全基本文件和工作基本文件 安全基本文件 (Secret Elementary File,SEF) 的内容包含用于用户识别和与加密有关的保密数据 ( 个人识别码 密钥等 ), 卡将利用这些数据进行安全管理 SEF 要在 MF 或 DF 建立后, 才能建立 建立后每个 KEY 都可以定义不同的修改权限 安全基本文件的内容不可被读出, 但可使用专门的指令来写入和修改 在 MF 和每个 DF 下只能建立 1 个安全基本文件, 但每个文件中的 KEY 和 PIN 的类型由用户指定 工作基本文件 (Working Elementary File,WEF) 包含了应用的实际数据, 其内容不被卡解释 在符合 WEF 的读 修改安全属性时, 可对其内容进行读取 修改 工作文件的个数和大小受到 MF 或 DF 所拥有空间的限制 整个文件系统的空间在 MF DF 和 EF 建立时被分配和确定, 以后在物理上不会发生变化 当访问 EF 时, 必须先选择相应的 MF 或 DF 可以从文件系统的任何位置选择 MF 通讯协议 多用途卡使用 ISO 中定义的异步半双工字符传输协议 (T=0), 字符型传输数据帧如下图 : TEL: FAX: 技术社区 :

279 图 7.29 SmartCard 数据帧 数据帧有 10 个数据位组成, 第一个是起始位, 后面跟 8 个数据位, 最后一个是奇偶校验位 在没有会话的时候,IO 信号保持高电平 智能卡会话过程中, 每个数据位占用的时间为 1 个 ETU(Elementary Time Unit),ETU 的单位是秒, 和智能卡的时钟信号呈线性关系 :ETU = F /(D f) 其中,f 为时钟频率,F 的初始值为 372,D 的初始值为 1( 初始 ETU) 关于 F 和 D 的值, 应该在收到智能卡的复位响应后, 根据响应提供的参数 (ATR, 具体定义参见 ISO7816-3) 设定 F 和 D 的值 ( 当前 ETU) 如果智能卡没有提供相应的参数, 将使用缺省值 一个 Byte 传输包括 1 个起始位,8 个数据位和一个较验位, 共 10 个 ETU 的时间 另外, 在两个帧中间, 需要至少 2 个 ETU 的保护时间 ( 具体为 (2+N)ETU), 故一个字节输出至少占用 12 个 ETU 的时间 如果两个帧起始位之间的时间超过 (960*D*W1)ETU, 则认为是传输超时, 该超时也可以用作一次数据传输 ( 多个数据帧 ) 的结束标志 PSAM 卡命令格式 PSAM 卡命令包含两部分 : 固定的四个字节命令头和长度可变的命令体, 其内容参见如下表格 : 命令头命令体 CLA INS P1 P2 Lc 数据域 Le CLA 字节指出命令的类型 如下表所述 : B7 B6 B5 B4 B3 B2 B1 B0 定义 外部命令内部命令安全报文传送不附加安全报文件传送 我们通常使用到的命令均不附加安全报文件传送, 因而命令的 CLA 字节为 : 0x00 或 0x80 INS 字节表示命令编码,P1 和 P2 为具体命令参数 TEL: FAX: 技术社区 :

280 Lc 字节表示数据的长度, 只有一个字节表示, 取值范围为 如果 Lc 为 0 表示没有数据域 Le 表示期望卡返回的数据长度, 由单字节表示, 取值范围 常用命令与应答编码 PSAM 卡的命令根据功能主要分为两大类 : 安全控管命令和电子存折 / 电子钱包命令两类 下表对平台应用中使用到的命令编码做了一简单归纳 : 命令指令类别编码命令类型用途 Get Challenge 安全控管命令 产生随机数 Select File 00 A4 安全控管命令 选择文件 INT_FOR_DES 安全控管命令 80 1A CRYPT 通用 DES 计算初始化 DES CRYPT 80 FA 安全控管命令 通用 DES 计算 Get Response 00 C0 安全控管命令 取响应 Read Binary 00 B0 安全控管命令 读二进制 Update Binary 00 D6 安全控管命令 修改二进制 Verify 安全控管命令 校验 PIN Read Record 00 B2 安全控管命令 读记录 Get Balance 80 5C 电子钱包命令 读余额 INT_FOR_LOA 电子钱包命令 D 圈存初始化 CREDIT_FOR_ 电子钱包命令 LOAD 圈存 正常返回码如下 : 状态码 含义说明 正常结束 61 XX 正常结束, 仍有 XX 个有效数据可取 工作原理 当使能智能卡控制器后, 控制器会对智能卡发出一个冷复位, 智能卡将根据自身的属性返回复位响应, 复位响应中包括工作模式 等待时间等一系列工作参数和状态, 后续的会话, 将按照智能卡提供的参数进行 如果冷复位之后控制器没有收到符合格式的复位响应, 控制器继续发出一个热复位, 如果智能卡对热复位仍然没有给出符合格式的复位响应, 控制器将结束会话, 并释放智能卡 智能卡的冷复位 热复位和释放时序, 符合 ISO7816 规范 对于冷复位和热复位, 复位响应是相同的 复位响应的内容由智能卡的工作模式决定 TEL: FAX: 技术社区 :

281 表格 3 T=0 模式下, 缺省复位响应 字段 值 描述 TS 3B 或者 3F 数据位正相编码还是反相编码 T0 6X TB1 和 TC1 存在,X 表示历史字节个数 TB1 00 编程电压 VPP 不存在 TC1 00~FF 额外的等待时间,FF 有特殊意义 表格 4 T=1 模式下, 缺省复位响应 字段 值 描述 TS 3B 或者 3F 数据位正相编码还是反相编码 T0 EX TB1 TC1 TD1 存在,X 表示历史字节个数 TB1 00 编程电压 VPP 不存在 TC1 00~FF 额外的等待时间,FF 有特殊意义 TD1 81 TA2 TB2 TC2 不存在,TD2 存在, 使用 T=1 模式 TD2 31 TA3 TB3 存在,TC3 TD3 不存在, 使用 T=1 模式 TA3 10~FE 返回 IFSI 的值 TB3 高 4 位 :0~4 低 4 位 :0~5 块等待时间 BWI:0~4 等待时间 CWI:0~5 TCK 校验字段 以下是关于 PSAM 卡应用的具体例子 MAC 加密应用 PSAM 卡作为多用途卡, 不同的应用将选择不同文件 相应的,MAC 加密应选择相应的文件 在 MAC 加密之前, 应该对通用 DES 计算初始化 最后进行 MAC 加密 选择文件 :{0x00,0xA4,0x04,0x0,0x05,0x11,0x22,0x33,0x44,0x55 通用 DES 计算初始化 :{0X80,0X1A,0X08,0X01,0X00 三次 DES 加密 : {0X80,0XFA,0X07,0X00,0X18,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0 X01,0X02,0X03,0X04,0X05,0X06,0X07,0X08,0X80,0X00,0X00,0X00,0X00,0X00, 0X00,0X00 {0X80,0XFA,0X03,0X00,0X18,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0 X88,0X88,0X88,0X88,0X88,0X88,0X88,0X88,0X80,0X00,0X00,0X00,0X00,0X00, 0X00,0X00 {0X80,0XFA,0X01,0X00,0X18,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0 X11,0X12,0X13,0X14,0X15,0X16,0X17,0X18,0X80,0X00,0X00,0X00,0X00,0X00, 0X00,0X00 TEL: FAX: 技术社区 :

282 发送每次命令时, 先发送前五个字节 ( 命令头 ) 数据域在命令头发送完之后发送 通过智能卡和接口设备之间的数据通信, 完成了一次 MAC 加密过程 超时机制 根据 ISO7816 规范, 如果两个数据帧的起始位之间和等待时间超过 960*D*W1 个 ETU, 则认为数据超时 (W1 和 D 由 ATR 给出 ) 超时到来后,SMC 控制器将重置状态机, 准备开始下一次数据交互 因此, 在上一次数据传输的超时到来之前, 由于 SMC 控制器处理于等待状态, 将无法进行下一次数据传输 在实际应用中, 如果不清楚一次命令交互会返回多少字节的响应, 可以利用超时作为数据传输的结束标志 如果确切知道当前命令返回的字节数, 可在收到足够数量的数据后即认为数据传输完成, 而不需要等待超时标志 需要注意的是, 使用第二种方法时, 由于此次操作未超时,SMC 控制器在本次操作的超时到来之前, 无法进行和卡片下一次的数据交互 为了提高通讯效率, 在 确认一次交互返回的数据量 的前提下, 可以人为地加速超时过程 即在数据交互之前, 将 D 和 W1 的值均设为 1( 不可以设为零 ) 在超时到来后再改回和卡片匹配的值 TEL: FAX: 技术社区 :

283 7.10 FSK 应用说明 CMX865 是系统通讯部分的核心器件, 是 CML 公司近年推出的一款低功耗调制解调芯片 ( 电话机信令收发集成电路 ) CMX865 包含 DTM F 编码解码器 V. 23 调制解调器, 具有铃流检测 话机摘机检测等功能, 它可以广泛应用于由线路提供电源的电话设备 该模块分为 2 部分 : 第一部分为电话线接口电路 DAA, 主要为模拟摘挂机电路以及防雷击电路 ; 第二部分为 CMX865 调制解调器及其外围电路, 包括振铃检测电路以及信号调理电路 CMX865 支持多种协议, 最高通讯速率为 1200 b/s, 对应协议为 BELL202 和 V.23, 调制方式为 FSK CMX865 通过 C-BUS 总线接口与 SEP4020 进行通讯 C-BUS 总线由类似 SPI 的同步串口 中断信号线 片选线组成 CMX865 调制解调器外围电路主要由振铃检测电路 接收发送端信号调理电路 以及 C-BUS 接口电路组成 CMX865 电话接口子板与主控板通过 C-BUS 通信进行数据传输 功能框图如下 : 典型应用的推荐电路如下 : 图 7.30 TEL: FAX: 技术社区 :

华恒家庭网关方案

华恒家庭网关方案 LINUX V1.5 1 2 1 2 LINUX WINDOWS PC VC LINUX WINDOWS LINUX 90% GUI LINUX C 3 REDHAT 9 LINUX PC TFTP/NFS http://www.hhcn.com/chinese/embedlinux-res.html minicom NFS mount C HHARM9-EDU 1 LINUX HHARM9-EDU

More information

static struct file_operations gpio_ctl_fops={ ioctl: gpio_ctl_ioctl, open : gpio_open, release: gpio_release, ; #defineled1_on() (GPBDAT &= ~0x1) #def

static struct file_operations gpio_ctl_fops={ ioctl: gpio_ctl_ioctl, open : gpio_open, release: gpio_release, ; #defineled1_on() (GPBDAT &= ~0x1) #def Kaise s 2410 Board setting [1]. Device Driver Device Driver Linux s Kernel ARM s kernel s3c2410_kernel2.4.18_r1.1_change.tar.bz2 /usr/src (1) #cd /usr/src (2) #tar xfj s3c2410_kernel2.4.18_r1.1_change.tar.bz2

More information

SEP4020 Linux2

SEP4020 Linux2 SEP4020 Linux2.6.16 SDK Develop Manual Version 3.4.4 南京博芯电子技术有限公司 2009 年 12 月 版权声明 本手册版权归属南京博芯电子技术有限公司所有, 并保留一切权力 没有南京博芯电子技术有限公司的许可 ( 书面形式 ), 任何单位及个人不得擅自摘录本手册部分或全部, 违者我们将追究其法律责任 TEL:025-83196327 FAX:025-83196326

More information

网名 鱼树 的学员聂龙浩, 学习 韦东山 Linux 视频第 2 期 时所写的笔记很详细, 供大家参考 也许有错漏, 请自行分辨 目录 驱动框架分析 内核中的理解 : 内核这样理解 :... 2 RTC 测试 RTC:

网名 鱼树 的学员聂龙浩, 学习 韦东山 Linux 视频第 2 期 时所写的笔记很详细, 供大家参考 也许有错漏, 请自行分辨 目录 驱动框架分析 内核中的理解 : 内核这样理解 :... 2 RTC 测试 RTC: 网名 鱼树 的学员聂龙浩, 学习 韦东山 Linux 视频第 2 期 时所写的笔记很详细, 供大家参考 也许有错漏, 请自行分辨 目录 驱动框架分析... 2 1. 2.4 内核中的理解 :... 2 2. 2.6 内核这样理解 :... 2 RTC... 6 1. 测试 RTC:... 11 1. 1. 修改 arch\arm\plat-s3c24xx\common-smdk.c... 11 2.

More information

DVK530/531扩展板

DVK530/531扩展板 DVK720 扩展板 驱动移植手册 2014.04.03 V1.0 版权声明 本手册所有权由深圳市微雪电子有限公司独家持有 未经本公司的书 面许可, 不得以任何方式或形式进行修改 分发或复制本文档的任何 部分, 否则一切后果由违者自负 版本更新记录 版本日期说明 V1.0 2014.04.03 初始发布 深圳市微雪电子有限公司 www.waveshare.net I 目录 版权声明... I 版本更新记录...

More information

Windows RTEMS 1 Danilliu MMI TCP/IP QEMU i386 QEMU ARM POWERPC i386 IPC PC104 uc/os-ii uc/os MMI TCP/IP i386 PORT Linux ecos Linux ecos ecos eco

Windows RTEMS 1 Danilliu MMI TCP/IP QEMU i386 QEMU ARM POWERPC i386 IPC PC104 uc/os-ii uc/os MMI TCP/IP i386 PORT Linux ecos Linux ecos ecos eco Windows RTEMS 1 Danilliu MMI TCP/IP 80486 QEMU i386 QEMU ARM POWERPC i386 IPC PC104 uc/os-ii uc/os MMI TCP/IP i386 PORT Linux ecos Linux ecos ecos ecos Email www.rtems.com RTEMS ecos RTEMS RTEMS Windows

More information

Abstract arm linux tool-chain root NET-Start! 2

Abstract arm linux tool-chain root NET-Start! 2 Lab III - Embedding Linux 1 Abstract arm linux tool-chain root NET-Start! 2 Part 1.4 Step1. tool-chain 4 Step2. PATH 4 Part 2 kernel 5 Step1. 5 Step2... 6 Step3...8 Part 3 root. 8 Step1. 8 Step2. 8 Part

More information

手册 doc

手册 doc 1. 2. 3. 3.1 3.2 3.3 SD 3.4 3.5 SD 3.6 3.7 4. 4.1 4.2 4.3 SD 4.4 5. 5.1 5.2 5.3 SD 6. 1. 1~3 ( ) 320x240~704x288 66 (2G SD 320x2401FPS ) 32M~2G SD SD SD SD 24V DC 3W( ) -10~70 10~90% 154x44x144mm 2. DVR106

More information

<4D6963726F736F667420576F7264202D20C7B6C8EBCABD6C696E7578BBF9B4A1CAB5D1E92E646F63>

<4D6963726F736F667420576F7264202D20C7B6C8EBCABD6C696E7578BBF9B4A1CAB5D1E92E646F63> 嵌 入 式 linux 基 础 实 验 1 内 核 配 置 及 编 译 1. 进 入 内 核 所 在 目 录 /opt/ruiva/xscale/linux-2.6.26 #cd /opt/ruiva/xscale/linux-2.6.26 2. 键 入 make menuconfig, 根 据 需 要 适 当 配 置 内 核 #make menuconfig 这 里 先 使 用 默 认 的 配 置,

More information

Microsoft Word - 在VMWare-5.5+RedHat-9下建立本机QTopia-2.1.1虚拟平台a.doc

Microsoft Word - 在VMWare-5.5+RedHat-9下建立本机QTopia-2.1.1虚拟平台a.doc 在 VMWare-5.5+RedHat-9 下建立 本机 QTopia-2.1.1 虚拟平台 张大海 2008-5-9 一 资源下载 1. 需要以下安装包 : tmake-1.13.tar.gz qtopia-free-source-2.1.1.tar.gz qt-embedded-2.3.10-free.tar.gz qt-x11-2.3.2.tar.gz qt-x11-free-3.3.4.tar.gz

More information

自由軟體教學平台

自由軟體教學平台 NCHC Opensource task force Steven Shiau steven@nchc.gov.tw National Center for High-Performance Computing Sep 10, 2002 1 Outline 1. 2. 3. Service DHCP, TFTP, NFS, NIS 4. 5. 2 DRBL (diskless remote boot

More information

DVK530/531扩展板

DVK530/531扩展板 DVK710 扩展板 驱动移植手册 2014.06.03 V1.0 版权声明 本手册所有权由深圳市微雪电子有限公司独家持有 未经本公司的书 面许可, 不得以任何方式或形式进行修改 分发或复制本文档的任何 部分, 否则一切后果由违者自负 版本更新记录 版本日期说明 V1.0 2014.06.03 初始发布 深圳市微雪电子有限公司 www.waveshare.netii I 目录版权声明... I 版本更新记录...

More information

Windows 2000 Server for T100

Windows 2000 Server for T100 2 1 Windows 95/98 Windows 2000 3.5 Windows NT Server 4.0 2 Windows DOS 3.5 T200 2002 RAID RAID RAID 5.1 Windows 2000 Server T200 2002 Windows 2000 Server Windows 2000 Server Windows 2000 Server 3.5 for

More information

自由軟體教學平台

自由軟體教學平台 NCHC Opensource task force DRBL steven@nchc.gov.tw, c00hkl00@nchc.gov.tw National Center for High-Performance Computing http://www.nchc.gov.tw Jan, 2003 1 2003/1/28 ( ) 09:00-10:30 10:40-12:00 Linux 13:00-14:30

More information

自由軟體教學平台

自由軟體教學平台 NCHC Opensource task force DRBL c00hkl00@nchc.gov.tw, steven@nchc.gov.tw National Center for High-Performance Computing http://www.nchc.gov.tw Dec, 2002 1 Outline 1. 2. DRBL 3. 4. Service DHCP, TFTP, NFS,

More information

. Outline 编译 Linux 在 QEMU 模拟器上运行制作带 grub 启动的磁盘映像...1 编译 Linux 在 QEMU 模拟器上运行...2 制作带 grub 启动的磁盘映像

. Outline 编译 Linux 在 QEMU 模拟器上运行制作带 grub 启动的磁盘映像...1 编译 Linux 在 QEMU 模拟器上运行...2 制作带 grub 启动的磁盘映像 .... 计算机应用教研室 @ 计算机学院嵌入式系统实验室 @ 苏州研究院中国科学技术大学 Fall 2010 . Outline 编译 Linux 在 QEMU 模拟器上运行制作带 grub 启动的磁盘映像...1 编译 Linux 在 QEMU 模拟器上运行...2 制作带 grub 启动的磁盘映像 . 编译 Linux 在 QEMU 模拟器上运行 qemu+linux-2.6.26.1. 准备模拟器.2.

More information

A Preliminary Implementation of Linux Kernel Virus and Process Hiding

A Preliminary Implementation of Linux Kernel Virus and Process Hiding 邵 俊 儒 翁 健 吉 妍 年 月 日 学 号 学 号 学 号 摘 要 结 合 课 堂 知 识 我 们 设 计 了 一 个 内 核 病 毒 该 病 毒 同 时 具 有 木 马 的 自 动 性 的 隐 蔽 性 和 蠕 虫 的 感 染 能 力 该 病 毒 获 得 权 限 后 会 自 动 将 自 身 加 入 内 核 模 块 中 劫 持 的 系 统 调 用 并 通 过 简 单 的 方 法 实 现 自 身 的

More information

<4D F736F F D20C7B6C8EBCABDCFB5CDB3BFAAB7A2CAB5D1E9CBC42E646F63>

<4D F736F F D20C7B6C8EBCABDCFB5CDB3BFAAB7A2CAB5D1E9CBC42E646F63> 嵌入式系统实验四 Linux 下设备驱动程序的开发 3.1 设备驱动程序的开发流程 进行嵌入式 Linux 系统的开发, 很大的工作量是为各种设备编写驱动程序 在 ARM 平台上开发嵌入式 Linux 的设备驱动程序与在其他平台上开发是一样的 总的来说, 实现一个嵌入式 Linux 设备驱动的大致流程如下 : (1) 查看原理图, 理解设备的工作原理 (2) 定义主设备号 (3) 在驱动程序中实现驱动的初始化

More information

<4D F736F F D20B5DA36D5C22020D7D6B7FBC9E8B1B8C7FDB6AF>

<4D F736F F D20B5DA36D5C22020D7D6B7FBC9E8B1B8C7FDB6AF> LINUX 设备驱动开发详解 作者 : 华清远见 第 6 章 字符设备驱动 Linux Linux 6.1 Linux cdev file_operations Linux 6.2 globalmem 6 9 6.3 6.1 globalmem seek() I/O globalmem 6.4 6.3 globalmem Linux 字符设备驱动结构 6.1.1 cdev 结构体 在 Linux 2.6

More information

1

1 SDT Uclinux SDT.alf.c 44blib.alf 44blib.c jtag ADS.alf.c make menuconfig make dep make clean make lib_only make user_only make romfs make image make uclinux ext2 cash lcd frambuffer 1 armsys-c uclinux

More information

AL-M200 Series

AL-M200 Series NPD4754-00 TC ( ) Windows 7 1. [Start ( )] [Control Panel ()] [Network and Internet ( )] 2. [Network and Sharing Center ( )] 3. [Change adapter settings ( )] 4. 3 Windows XP 1. [Start ( )] [Control Panel

More information

EK-STM32F

EK-STM32F STMEVKIT-STM32F10xx8 软 件 开 发 入 门 指 南 目 录 1 EWARM 安 装... 1 1.1 第 一 步 : 在 线 注 册... 1 1.2 第 二 步 : 下 载 软 件... 2 1.3 第 三 步 : 安 装 EWARM... 3 2 基 于 STMEVKIT-STM32F10xx8 的 示 例 代 码 运 行... 6 2.1 GPIO Demo... 6 2.2

More information

Microsoft Word - PS2_linux_guide_cn.doc

Microsoft Word - PS2_linux_guide_cn.doc Linux For $ONY PlayStatioin2 Unofficall General Guide Language: Simplified Chinese First Write By Beter Hans v0.1 Mail: hansb@citiz.net Version: 0.1 本 人 是 菜 鸟 + 小 白 欢 迎 指 正 错 误 之 处, 如 果 您 有 其 他 使 用 心 得

More information

AL-MX200 Series

AL-MX200 Series PostScript Level3 Compatible NPD4760-00 TC Seiko Epson Corporation Seiko Epson Corporation ( ) Seiko Epson Corporation Seiko Epson Corporation Epson Seiko Epson Corporation Apple Bonjour ColorSync Macintosh

More information

嵌入式Linux知识培训

嵌入式Linux知识培训 嵌入式 Linux 知识培训 主要包括以下四部分内容 : 一 嵌入式 Linux 开发的基本知识 二 Linux 下使用 C 语言进行系统开发 三 面向嵌入式 Linux 的 GUI 系统的体系结构及二次开发 四 基于 Linux OS Smart Phone 的体系结构及开发内容 李玉东 第一部分 基础知识 嵌入式 Linux 软件系统的构成 1.BootLoader 2. Kernel 3.FileSystem

More information

CC213

CC213 : (Ken-Yi Lee), E-mail: feis.tw@gmail.com 49 [P.51] C/C++ [P.52] [P.53] [P.55] (int) [P.57] (float/double) [P.58] printf scanf [P.59] [P.61] ( / ) [P.62] (char) [P.65] : +-*/% [P.67] : = [P.68] : ,

More information

(Load Project) (Save Project) (OffLine Mode) (Help) Intel Hex Motor

(Load Project) (Save Project) (OffLine Mode) (Help) Intel Hex Motor 1 4.1.1.1 (Load) 14 1.1 1 4.1.1.2 (Save) 14 1.1.1 1 4.1.2 (Buffer) 16 1.1.2 1 4.1.3 (Device) 16 1.1.3 1 4.1.3.1 (Select Device) 16 2 4.1.3.2 (Device Info) 16 2.1 2 4.1.3.3 (Adapter) 17 2.1.1 CD-ROM 2 4.1.4

More information

C/C++ - 文件IO

C/C++ - 文件IO C/C++ IO Table of contents 1. 2. 3. 4. 1 C ASCII ASCII ASCII 2 10000 00100111 00010000 31H, 30H, 30H, 30H, 30H 1, 0, 0, 0, 0 ASCII 3 4 5 UNIX ANSI C 5 FILE FILE 6 stdio.h typedef struct { int level ;

More information

05_資源分享-NFS及NIS.doc

05_資源分享-NFS及NIS.doc 5 NFS NFS Server NFS Client NIS NIS 5-0 (Network File System, NFS) Unix NFS mount NFS... Network Information Service NIS Linux NIS NIS NIS / / /etc/passwd /etc/group NFS NIS 5-1 NFS 5-1-1 NFS NFS Network

More information

P4i45GL_GV-R50-CN.p65

P4i45GL_GV-R50-CN.p65 1 Main Advanced Security Power Boot Exit System Date System Time Floppy Drives IDE Devices BIOS Version Processor Type Processor Speed Cache Size Microcode Update Total Memory DDR1 DDR2 Dec 18 2003 Thu

More information

一 登录 crm Mobile 系统 : 输入 ShijiCare 用户名和密码, 登录系统, 如图所示 : 第 2 页共 32 页

一 登录 crm Mobile 系统 : 输入 ShijiCare 用户名和密码, 登录系统, 如图所示 : 第 2 页共 32 页 第 1 页共 32 页 crm Mobile V1.0 for IOS 用户手册 一 登录 crm Mobile 系统 : 输入 ShijiCare 用户名和密码, 登录系统, 如图所示 : 第 2 页共 32 页 二 crm Mobile 界面介绍 : 第 3 页共 32 页 三 新建 (New) 功能使用说明 1 选择产品 第 4 页共 32 页 2 填写问题的简要描述和详细描述 第 5 页共

More information

ESP-Jumpstart

ESP-Jumpstart 2016-2019 2019 08 08 Contents 1 3 1.1 ESP32.............................. 3 1.2.................................................. 5 2 7 2.1............................................. 7 2.2 ESP-IDF............................................

More information

ARM JTAG实时仿真器安装使用指南

ARM JTAG实时仿真器安装使用指南 ARM JTAG Version 1.31 2003. 11. 12 ARM JTAG ARM JTAG.3 ARM 2.1.4 2.2.4 ARM JTAG 3.1 18 3.2 18 3.2.1 Multi-ICE Server.18 3.2.2 ADS..21 ARM JTAG 4.1 Multi-ICE Server 33 4.1.1 Multi-ICE Server..... 33 4.1.2

More information

Ioncube Php Encoder 8 3 Crack 4. llamaba octobre traslado General Search colony

Ioncube Php Encoder 8 3 Crack 4. llamaba octobre traslado General Search colony Ioncube Php Encoder 8 3 Crack 4 ->>->>->> DOWNLOAD 1 / 5 2 / 5 Press..the..General..Tools..category4Encrypt..and..protect..files..with..PHP..encoding,..encryption,..ob fuscation..and..licensing... 2016

More information

Microsoft Word - install_manual-V _CN.docx

Microsoft Word - install_manual-V _CN.docx NO TASK Q-Sign Install Manual PAGE 1/28 Q-Sign INSTALL MANUAL Version 3.0 Server Manager Client Codec NO TASK Q-Sign Install Manual PAGE 2/28 History DATE Contents Name Ver. Remark 2009-02-11 Q-Sign Ver.

More information

WinMDI 28

WinMDI 28 WinMDI WinMDI 2 Region Gate Marker Quadrant Excel FACScan IBM-PC MO WinMDI WinMDI IBM-PC Dr. Joseph Trotter the Scripps Research Institute WinMDI HP PC WinMDI WinMDI PC MS WORD, PowerPoint, Excel, LOTUS

More information

Cadence SPB 15.2 VOICE Cadence SPB 15.2 PC Cadence 3 (1) CD1 1of 2 (2) CD2 2of 2 (3) CD3 Concept HDL 1of 1

Cadence SPB 15.2 VOICE Cadence SPB 15.2 PC Cadence 3 (1) CD1 1of 2 (2) CD2 2of 2 (3) CD3 Concept HDL 1of 1 Cadence SPB 15.2 VOICE 2005-05-07 Cadence SPB 15.2 PC Cadence 3 (1) CD1 1of 2 (2) CD2 2of 2 (3) CD3 Concept HDL 1of 1 1 1.1 Cadence SPB 15.2 2 Microsoft 1.1.1 Windows 2000 1.1.2 Windows XP Pro Windows

More information

Serial ATA ( Silicon Image SiI3114)...2 (1) SATA... 2 (2) B I O S S A T A... 3 (3) RAID BIOS RAID... 5 (4) S A T A... 8 (5) S A T A... 10

Serial ATA ( Silicon Image SiI3114)...2 (1) SATA... 2 (2) B I O S S A T A... 3 (3) RAID BIOS RAID... 5 (4) S A T A... 8 (5) S A T A... 10 Serial ATA ( Silicon Image SiI3114)...2 (1) SATA... 2 (2) B I O S S A T A... 3 (3) RAID BIOS RAID... 5 (4) S A T A... 8 (5) S A T A... 10 Ác Åé å Serial ATA ( Silicon Image SiI3114) S A T A (1) SATA (2)

More information

エスポラージュ株式会社 住所 : 東京都江東区大島 東急ドエルアルス大島 HP: ******************* * 关于 Java 测试试题 ******

エスポラージュ株式会社 住所 : 東京都江東区大島 東急ドエルアルス大島 HP:  ******************* * 关于 Java 测试试题 ****** ******************* * 关于 Java 测试试题 ******************* 問 1 运行下面的程序, 选出一个正确的运行结果 public class Sample { public static void main(string[] args) { int[] test = { 1, 2, 3, 4, 5 ; for(int i = 1 ; i System.out.print(test[i]);

More information

安之谋 HMI972 人机界面 CE 开发手册 版权声明 本手册版权归属北京安之谋科技有限责任公司 ( 以下简称 安之谋科技 ) 所有, 并保留一切权力 非经安之谋科技同意 ( 书面形式 ), 任何单位及个人不得擅自摘录本手册部分或全部, 违者我们将追究其法律责任

安之谋 HMI972 人机界面 CE 开发手册 版权声明 本手册版权归属北京安之谋科技有限责任公司 ( 以下简称 安之谋科技 ) 所有, 并保留一切权力 非经安之谋科技同意 ( 书面形式 ), 任何单位及个人不得擅自摘录本手册部分或全部, 违者我们将追究其法律责任 版权声明 本手册版权归属北京安之谋科技有限责任公司 ( 以下简称 安之谋科技 ) 所有, 并保留一切权力 非经安之谋科技同意 ( 书面形式 ), 任何单位及个人不得擅自摘录本手册部分或全部, 违者我们将追究其法律责任 北京安之谋科技有限公司, 多年来一直致力于高质量嵌入式软硬件的开发 由安之谋科技提供 HMI972 人机界面平台可运行独家提供的 CE6, 除了具有常见的功能之外, 还提供了各种方便客户二次开发和生产的功能

More information

Guide to Install SATA Hard Disks

Guide to Install SATA Hard Disks SATA RAID 1. SATA. 2 1.1 SATA. 2 1.2 SATA 2 2. RAID (RAID 0 / RAID 1 / JBOD).. 4 2.1 RAID. 4 2.2 RAID 5 2.3 RAID 0 6 2.4 RAID 1.. 10 2.5 JBOD.. 16 3. Windows 2000 / Windows XP 20 1. SATA 1.1 SATA Serial

More information

0 配置 Host MIB 设备 V ( 简体版 ) 0 Update: 2016/1/30

0 配置 Host MIB 设备 V ( 简体版 ) 0 Update: 2016/1/30 0 配置 Host MIB 设备 V 1.1.2 ( 简体版 ) 0 Update: 2016/1/30 前言 N-Reporter 支持 Host Resource MIB 监控主机 (Host) 状态, 本文件描述 N-Reporter 用户如何配置 Host MIB 设备 文件章节如下 : 1. 配置 Windows Server 2003... 2 1-1.Windows Server 2003

More information

untitled

untitled TS-411U Turbo Server TS-411U Turbo Server ( : 1.0.0) 2005 2005 12 8-2 - 1. 2. TS-411U Turbo Server - 3 - ... 7 1.1... 7 1.2... 8 1.3... 9 TS-411U... 10 2.1... 10 2.2... 14 2.3 TS-411U... 15 LCD... 17...

More information

F515_CS_Book.book

F515_CS_Book.book /USB , ( ) / L R 1 > > > 2, / 3 L 1 > > > 2 + - 3, 4 L 1 了解显示屏上显示的图标 Wap 信箱收到一条 Wap push 信息 ( ) GSM 手机已连接到 GSM 网络 指示条越多, 接收质量越好 2 ...........................4.............................. 4 Micro SD (

More information

Windows 2000 Server for T100

Windows 2000 Server for T100 T200 3020 Windows 2000 Advanced Server /Windows NT 4.0 Server /Redhat Linux7.3 SCO UnixWare7.1.1 Novell NetWare5.0 1. Windows 2000 Advanced Server / 2. Windows NT 4.0 Server / 3. Redhat Linux7.3 4. SCO

More information

Microsoft Word - 第5章.doc

Microsoft Word - 第5章.doc 目 录 及 权 限 管 理 随 着 的 不 断 发 展, 越 来 越 多 的 人 开 始 使 用, 对 于 那 些 刚 接 触 的 人 来 说, 恐 怕 最 先 感 到 困 惑 的 就 是 那 些 不 明 不 白 的 目 录 了 同 样, 系 统 是 一 个 典 型 的 多 用 户 系 统 为 了 保 护 系 统 的 安 全 性, 系 统 对 不 同 用 户 访 问 同 一 文 件 或 目 录 的

More information

Chapter #

Chapter # 第三章 TCP/IP 协议栈 本章目标 通过本章的学习, 您应该掌握以下内容 : 掌握 TCP/IP 分层模型 掌握 IP 协议原理 理解 OSI 和 TCP/IP 模型的区别和联系 TCP/IP 介绍 主机 主机 Internet TCP/IP 早期的协议族 全球范围 TCP/IP 协议栈 7 6 5 4 3 应用层表示层会话层传输层网络层 应用层 主机到主机层 Internet 层 2 1 数据链路层

More information

Serial ATA ( Nvidia nforce430)...2 (1) SATA... 2 (2) B I O S S A T A... 3 (3) RAID BIOS RAID... 6 (4) S A T A... 9 (5) S A T A (6) Microsoft Win

Serial ATA ( Nvidia nforce430)...2 (1) SATA... 2 (2) B I O S S A T A... 3 (3) RAID BIOS RAID... 6 (4) S A T A... 9 (5) S A T A (6) Microsoft Win Serial ATA ( Nvidia nforce430)...2 (1) SATA... 2 (2) B I O S S A T A... 3 (3) RAID BIOS RAID... 6 (4) S A T A... 9 (5) S A T A... 11 (6) Microsoft Windows 2000... 14 Ác Åé å Serial ATA ( Nvidia nforce430)

More information

IP505SM_manual_cn.doc

IP505SM_manual_cn.doc IP505SM 1 Introduction 1...4...4...4...5 LAN...5...5...6...6...7 LED...7...7 2...9...9...9 3...11...11...12...12...12...14...18 LAN...19 DHCP...20...21 4 PC...22...22 Windows...22 TCP/IP -...22 TCP/IP

More information

untitled

untitled MySQL DBMS under Win32 Editor: Jung Yi Lin, Database Lab, CS, NCTU, 2005/09/16 MySQL 料 理 MySQL 兩 Commercial License 利 GPL MySQL http://www.mysql.com Developer Zone http://www.mysql.com Download 連 連 MySQL

More information

投影片 1

投影片 1 類 Linux (, VBird) 2008/03/28 Linux 1 Linux man page / 流 例 2008/03/28 Linux 2 Linux 2008/03/28 Linux 3 Linux CPU RAM 路 2008/03/28 Linux 4 Linux Linux 2008/03/28 Linux 5 Linux (sector) 理 量 512bytes (cylinder)

More information

C/C++ - 字符输入输出和字符确认

C/C++ - 字符输入输出和字符确认 C/C++ Table of contents 1. 2. getchar() putchar() 3. (Buffer) 4. 5. 6. 7. 8. 1 2 3 1 // pseudo code 2 read a character 3 while there is more input 4 increment character count 5 if a line has been read,

More information

Microsoft Word - 正文.doc

Microsoft Word - 正文.doc 1 2 1 2 3 4 5 6 7 8 9 10 3 1 150 2 150 1 1 1.1 1.1.1 1.2 1.2.1 1.2.2 1.2.3 1.3 1.3.1 1.3.2 1.4 1.4.1 CPU 1.4.2 I/O 1.4.3 I/O 1.5 1.5.1 CISC RISC 1.5.2 1.5.3 1.6 1.6.1 1.6.2 N 1.6.3 2 2.1 2.1.1 2.1.2 2.1.3

More information

Chapter 2

Chapter 2 2 (Setup) ETAP PowerStation ETAP ETAP PowerStation PowerStation PowerPlot ODBC SQL Server Oracle SQL Server Oracle Windows SQL Server Oracle PowerStation PowerStation PowerStation PowerStation ETAP PowerStation

More information

775i65PE_BIOS_CN.p65

775i65PE_BIOS_CN.p65 1 Main H/W Monitor Boot Security Exit System Overview System Time System Date [ 14:00:09] [Wed 10/20/2004] BIOS Version : 775i65PE BIOS P1.00 Processor Type : Intel (R) CPU 3.20 GHz Processor Speed : 3200

More information

Ch03_嵌入式作業系統建置_01

Ch03_嵌入式作業系統建置_01 Chapter 3 CPU Motorola DragonBall ( Palm PDA) MIPS ( CPU) Hitachi SH (Sega DreamCast CPU) ARM StrongARM CPU CPU RISC (reduced instruction set computer ) CISC (complex instruction set computer ) DSP(digital

More information

FY.DOC

FY.DOC 高 职 高 专 21 世 纪 规 划 教 材 C++ 程 序 设 计 邓 振 杰 主 编 贾 振 华 孟 庆 敏 副 主 编 人 民 邮 电 出 版 社 内 容 提 要 本 书 系 统 地 介 绍 C++ 语 言 的 基 本 概 念 基 本 语 法 和 编 程 方 法, 深 入 浅 出 地 讲 述 C++ 语 言 面 向 对 象 的 重 要 特 征 : 类 和 对 象 抽 象 封 装 继 承 等 主

More information

RTX3.2.0标准版 - 技术白皮书

RTX3.2.0标准版 - 技术白皮书 一 铭 操 作 系 统 技 术 白 皮 书 广 西 一 铭 软 件 股 份 有 限 公 司 版 权 声 明 本 书 版 权 归 广 西 一 铭 软 件 股 份 有 限 公 司 所 有, 并 保 留 对 本 文 档 及 声 明 的 最 终 解 释 权 和 修 改 权 本 文 件 中 出 现 的 任 何 文 字 叙 述 文 档 格 式 插 图 照 片 方 法 过 程 等 内 容, 除 另 有 特 别 说

More information

Basic System Administration

Basic System Administration 基 本 系 统 管 理 ESX Server 3.5 ESX Server 3i 版 本 3.5 Virtual Center 2.5 基 本 管 理 指 南 基 本 管 理 指 南 修 订 时 间 :20080410 项 目 :VI-CHS-Q208-490 我 们 的 网 站 提 供 最 新 的 技 术 文 档, 网 址 为 : http://www.vmware.com/cn/support/

More information

K7VT2_QIG_v3

K7VT2_QIG_v3 ............ 1 2 3 4 5 [R] : Enter Raid setup utility 6 Press[A]keytocreateRAID RAID Type: JBOD RAID 0 RAID 1: 2 7 RAID 0 Auto Create Manual Create: 2 RAID 0 Block Size: 16K 32K

More information

audiogram3 Owners Manual

audiogram3 Owners Manual USB AUDIO INTERFACE ZH 2 AUDIOGRAM 3 ( ) * Yamaha USB Yamaha USB ( ) ( ) USB Yamaha (5)-10 1/2 AUDIOGRAM 3 3 MIC / INST (XLR ) (IEC60268 ): 1 2 (+) 3 (-) 2 1 3 Yamaha USB Yamaha Yamaha Steinberg Media

More information

P4V88+_BIOS_CN.p65

P4V88+_BIOS_CN.p65 1 Main H/W Monitor Boot Security Exit System Overview System Time System Date [ 17:00:09] [Wed 12/22/2004] BIOS Version : P4V88+ BIOS P1.00 Processor Type : Intel (R) Pentium (R) 4 CPU 2.40 GHz Processor

More information

P4Dual-915GL_BIOS_CN.p65

P4Dual-915GL_BIOS_CN.p65 1 Main H/W Monitor Boot Security Exit System Overview System Time System Date Total Memory DIMM 1 DIMM 2 [ 14:00:09] [Wed 01/05/2005] BIOS Version : P4Dual-915GL BIOS P1.00 Processor Type : Intel (R) Pentium

More information

ebook71-13

ebook71-13 13 I S P Internet 13. 2. 1 k p p p P P P 13. 2. 2 1 3. 2. 3 k p p p 1 3. 2. 4 l i n u x c o n f P P P 13. 2. 5 p p p s e t u p 13. 2. 6 p p p s e t u p P P P 13. 2. 7 1 3. 2. 8 C a l d e r a G U I 13.

More information

嵌入式工程师考纲大纲(中级)

嵌入式工程师考纲大纲(中级) ARM9 嵌入式系统设计与开发应用 教学大纲 编写 : 熊茂华 本教材是为中国电子学会嵌入式设计工程师考试指定教材, 根据嵌入式设计工程师考试大纲 ( 中级 ) 要求, 制订了 ARM9 嵌入式系统设计与开发应用 课程的教学大纲 课程能力目标 : 通过本课程的教学, 掌握嵌入式应用系统的基本结构 嵌入式硬件接口和软件系统设计的方法 ; 利用嵌入式开发工具 ADS 1.2 开发基于 μc/os-ii

More information

uClinux for blackfin

uClinux for blackfin uclinux Blackfin support@besovideo.com QQ 21ic http://bbs.21ic.com/club/bbs/bbsview.asp?boardid=51 24! support@besovide o.com R&D BF561 Linux C MemoryMAP 32 X86 *((volatile unsigned short *)(0x10000300))=0xf0c0;

More information

T

T T10452 2015 5 Copyright ASUSTeK Computer Inc. All rights reserved. http://support.asus.com 0800-093-456 1 2 2 筆記型電腦使用手冊 使用手冊... 7 手冊... 8... 8... 8... 9 使用... 9...10...10 筆記型電腦...12...12...16...18...20...22

More information

一个开放源码的嵌入式仿真环境 ― SkyEye

一个开放源码的嵌入式仿真环境 ― SkyEye SkyEye SkyEye http://hpclab.cs.tsinghua.edu.cn/~skyeye/ I hear and I forget, I see and I remember, I do and I understand. SkyEye SkyEye SkyEye SkyEye SkyEye 1. SkyEye PC pervasive computing PC I O PDA

More information

P4VM800_BIOS_CN.p65

P4VM800_BIOS_CN.p65 1 Main H/W Monitor Boot Security Exit System Overview System Time System Date [ 17:00:09] [Fri 02/25/2005] BIOS Version : P4VM800 BIOS P1.00 Processor Type : Intel (R) Pentium (R) 4 CPU 2.40 GHz Processor

More information

1.ai

1.ai HDMI camera ARTRAY CO,. LTD Introduction Thank you for purchasing the ARTCAM HDMI camera series. This manual shows the direction how to use the viewer software. Please refer other instructions or contact

More information

C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 5 月 3 日 1

C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 5 月 3 日 1 C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 月 3 日 1 1 INPUTOUTPUT 1 InputOutput 题目描述 用 cin 输入你的姓名 ( 没有空格 ) 和年龄 ( 整数 ), 并用 cout 输出 输入输出符合以下范例 输入 master 999 输出 I am master, 999 years old. 注意 "," 后面有一个空格,"." 结束,

More information

六域链联盟 SDChain-Matrix 节点搭建指南 2018/07/26 Version : 1.0.0

六域链联盟 SDChain-Matrix 节点搭建指南 2018/07/26 Version : 1.0.0 SDChain-Matrix 节点搭建指南 目录 1 环境要求... 3 2 软件下载... 4 3 安装部署... 4 3.1 部署可执行程序目录... 4 3.2 部署配置文件目录... 4 3.3 部署数据库文件目录... 4 3.4 部署日志文件目录... 4 3.5 部署依赖库文件目录... 4 4 配置参数... 5 5 启动运行... 7 5.1 普通模式启动... 7 5.2 加载启动模式...

More information

Microsoft Word - 实用案例.doc

Microsoft Word - 实用案例.doc 计 算 机 系 统 应 用 2009 年 第 12 期 嵌 入 式 Linux 下 温 湿 度 传 感 器 的 设 计 与 实 现 1 Design and Implementation of Temperature and Humidity Sensor Based on Embedded Linux 陈 博 刘 锦 高 ( 华 东 师 范 大 学 电 子 科 学 技 术 系 上 海 200241)

More information

SL2511 SR Plus 操作手冊_單面.doc

SL2511 SR Plus 操作手冊_單面.doc IEEE 802.11b SL-2511 SR Plus SENAO INTERNATIONAL CO., LTD www.senao.com - 1 - - 2 - .5 1-1...5 1-2...6 1-3...6 1-4...7.9 2-1...9 2-2 IE...11 SL-2511 SR Plus....13 3-1...13 3-2...14 3-3...15 3-4...16-3

More information

chap07.key

chap07.key #include void two(); void three(); int main() printf("i'm in main.\n"); two(); return 0; void two() printf("i'm in two.\n"); three(); void three() printf("i'm in three.\n"); void, int 标识符逗号分隔,

More information

Symantec™ Sygate Enterprise Protection 防护代理安装使用指南

Symantec™ Sygate Enterprise Protection 防护代理安装使用指南 Symantec Sygate Enterprise Protection 防 护 代 理 安 装 使 用 指 南 5.1 版 版 权 信 息 Copyright 2005 Symantec Corporation. 2005 年 Symantec Corporation 版 权 所 有 All rights reserved. 保 留 所 有 权 利 Symantec Symantec 徽 标 Sygate

More information

The golden pins of the PCI card can be oxidized after months or years

The golden pins of the PCI card can be oxidized after months or years Q. 如何在 LabWindows/CVI 編譯 DAQ Card 程式? A: 請參考至下列步驟 : 步驟 1: 安裝驅動程式 1. 安裝 UniDAQ 驅動程式 UniDAQ 驅動程式下載位置 : CD:\NAPDOS\PCI\UniDAQ\DLL\Driver\ ftp://ftp.icpdas.com/pub/cd/iocard/pci/napdos/pci/unidaq/dll/driver/

More information

Ác Åé å Serial ATA ( Sil3132) S A T A (1) SATA (2) BIOS SATA (3)* RAID BIOS RAID (4) SATA (5) SATA (a) S A T A ( S A T A R A I D ) (b) (c) Windows XP

Ác Åé å Serial ATA ( Sil3132) S A T A (1) SATA (2) BIOS SATA (3)* RAID BIOS RAID (4) SATA (5) SATA (a) S A T A ( S A T A R A I D ) (b) (c) Windows XP Serial ATA ( Sil3132)...2 (1) SATA... 2 (2) B I O S S A T A... 3 (3) RAID BIOS RAID... 6 (4) S A T A... 10 (5) S A T A... 12 Ác Åé å Serial ATA ( Sil3132) S A T A (1) SATA (2) BIOS SATA (3)* RAID BIOS

More information

1 Project New Project 1 2 Windows 1 3 N C test Windows uv2 KEIL uvision2 1 2 New Project Ateml AT89C AT89C51 3 KEIL Demo C C File

1 Project New Project 1 2 Windows 1 3 N C test Windows uv2 KEIL uvision2 1 2 New Project Ateml AT89C AT89C51 3 KEIL Demo C C File 51 C 51 51 C C C C C C * 2003-3-30 pnzwzw@163.com C C C C KEIL uvision2 MCS51 PLM C VC++ 51 KEIL51 KEIL51 KEIL51 KEIL 2K DEMO C KEIL KEIL51 P 1 1 1 1-1 - 1 Project New Project 1 2 Windows 1 3 N C test

More information

Microsoft Word - linux命令及建议.doc

Microsoft Word - linux命令及建议.doc Linux 操 作 系 统 命 令 集 1 基 本 命 令 查 看 系 统 信 息 : uname -a 修 改 密 码 : passwd 退 出 : logout(exit) 获 取 帮 助 : man commands 2 文 件 和 目 录 命 令 显 示 当 前 工 作 目 录 : pwd 改 变 所 在 目 录 : cd cd - 切 换 到 上 一 次 使 用 的 目 录 cd 切 换

More information

f2.eps

f2.eps 前 言, 目 录 产 品 概 况 1 SICAM PAS SICAM 电 力 自 动 化 系 统 配 置 和 使 用 说 明 配 置 2 操 作 3 实 时 数 据 4 人 机 界 面 5 SINAUT LSA 转 换 器 6 状 态 与 控 制 信 息 A 版 本 号 : 08.03.05 附 录, 索 引 安 全 标 识 由 于 对 设 备 的 特 殊 操 作 往 往 需 要 一 些 特 殊 的

More information

Serial ATA ( nvidia nforce4 Ultra/SLI)...2 (1) SATA... 2 (2) B I O S S A T A... 3 (3) RAID BIOS RAID... 6 (4) S A T A... 9 (5) S A T A (6) Micro

Serial ATA ( nvidia nforce4 Ultra/SLI)...2 (1) SATA... 2 (2) B I O S S A T A... 3 (3) RAID BIOS RAID... 6 (4) S A T A... 9 (5) S A T A (6) Micro Serial ATA ( nvidia nforce4 Ultra/SLI)...2 (1) SATA... 2 (2) B I O S S A T A... 3 (3) RAID BIOS RAID... 6 (4) S A T A... 9 (5) S A T A... 11 (6) Microsoft Windows 2000... 14 Ác Åé å Serial ATA ( nvidia

More information

微雪电子 Open407V-D 实验手册 Open407V-D 实验手册 目录 准备工作... 2 ADC+DMA... 2 CAN1 TO CAN2-Normal... 3 DCMI_OV DCMI_OV I2C... 6 L

微雪电子   Open407V-D 实验手册 Open407V-D 实验手册 目录 准备工作... 2 ADC+DMA... 2 CAN1 TO CAN2-Normal... 3 DCMI_OV DCMI_OV I2C... 6 L Open407V-D 实验手册 目录 准备工作... 2 ADC+DMA... 2 CAN1 TO CAN2-Normal... 3 DCMI_OV7670... 4 DCMI_OV9655... 5 I2C... 6 LCD-HY32D_FSMC... 7 Nand Flash_PCB0... 8 Nand Flash_SCB0... 9 SD_FatFS... 11 SDIO... 12 SPI...

More information

V39用户手册0227.doc

V39用户手册0227.doc 300 2004 (FCC) FCC I/O B Cet appareil numérique de la classe B respecte toutes les exigences du Réglement sur le matériel brouilieur du Canada. Windows Windows 98 Windows 2000 Windows ME Windows XP Microsoft

More information

Data Server_new_.doc

Data Server_new_.doc 0i B/C Data Server Windows 2000 Window XP Windows XP FTP FANUC Data Server FTP liwei@beijing-fanuc 1 06-10-8 Content 1. /...3 1.1...3 1.2...3 1.3 CNC...3 2....5 2.1 STORAGE...5 2.2 FTP...6 2.3 BUFFER...7

More information

Microsoft PowerPoint - BECKHOFF技术_ADS通讯 [Compatibility Mode]

Microsoft PowerPoint - BECKHOFF技术_ADS通讯 [Compatibility Mode] 的架构 ADS 的通讯机制 ADS-Client Request -> Confirmation Indication

More information

(Guangzhou) AIT Co, Ltd V 110V [ ]! 2

(Guangzhou) AIT Co, Ltd V 110V [ ]! 2 (Guangzhou) AIT Co, Ltd 020-84106666 020-84106688 http://wwwlenxcn Xi III Zebra XI III 1 (Guangzhou) AIT Co, Ltd 020-84106666 020-84106688 http://wwwlenxcn 230V 110V [ ]! 2 (Guangzhou) AIT Co, Ltd 020-84106666

More information

+01-10_M5A_C1955.p65

+01-10_M5A_C1955.p65 Notebook PC User s Manual C1955 1.01 2005 4 2 50 70 3 (0 30 ) (50 122 ) 4 pre-load Fn+F7 5 ...2...3...6 1-1...12...12...13...14...15...16...17 1-2...18 1-3...20...20...21...21...21...21...22...22...22...22...23...23

More information

Microsoft Word zw

Microsoft Word zw 第 1 章 Android 概述 学习目标 : Android Android Android Studio Android Android APK 1.1 1. 智能手机的定义 Smartphone 2. 智能手机的发展 1973 4 3 PC IBM 1994 IBM Simon PDA PDA Zaurus OS 1996 Nokia 9000 Communicator Nokia 9000

More information

LSI U320 SCSI卡用户手册.doc

LSI U320 SCSI卡用户手册.doc V1.0 Ultra320 SCSI SCSI 2004 7 PentiumIntel MS-DOS Windows Novell Netware Novell Sco Unix Santa Cruz Operation LSI U320 SCSI SCSI SCSI Integrated Mirroring/Integrated Striping BIOS Firmware LSI U320 SCSI

More information

Ác Åé å Serial ATA ( nvidia nforce4 SLI) S A T A (1) SATA (2) BIOS SATA (3)* RAID BIOS RAID (4) SATA (5) SATA (a) S A T A ( S A T A R A I D ) (b) (c)

Ác Åé å Serial ATA ( nvidia nforce4 SLI) S A T A (1) SATA (2) BIOS SATA (3)* RAID BIOS RAID (4) SATA (5) SATA (a) S A T A ( S A T A R A I D ) (b) (c) Serial ATA ( nvidia nforce4 SLI)...2 (1) SATA... 2 (2) B I O S S A T A... 3 (3) RAID BIOS RAID... 6 (4) S A T A... 9 (5) S A T A... 11 (6) Microsoft Windows 2000... 14 Ác Åé å Serial ATA ( nvidia nforce4

More information

ebook70-22

ebook70-22 2 2 L i n u x f s t a b X 11 L i n u x L i n u x L i n u x D O S Wi n d o w s L i n u x O p e n L i n u x / u s r / m a n / m a n 5 f s t a b m o u n t m o u n t L i n u x 22.1 OpenLinux L i n u x U N

More information

<C8EBC3C5C6AAA3A8B5DA31D5C2A3A92E696E6464>

<C8EBC3C5C6AAA3A8B5DA31D5C2A3A92E696E6464> 第 1 章 进入 Photoshop 的全新世界 本章导读 Photoshop 1 1.1 Photoshop CS6 Photoshop Photoshop 1.1.1 Photoshop POP 1-1 图 1-1 平面广告效果 1.1.2 Photoshop 1-2 Photoshop CS6 Photoshop CS6 Photoshop CS6 Extended 3D 3 Photoshop

More information

untitled

untitled V3041A-J/V3042A-J IP-SAN/NAS Infinova Infinova Infinova Infinova www.infinova.com.cn Infinova Infinova Infinova 1 2 1 2 V3041A-16R-J V3041A-24R-J V3042A-16R-J V3042A-24R-J V3049-EXD-R16 V3049-EXD-R24 ...

More information

ebook140-9

ebook140-9 9 VPN VPN Novell BorderManager Windows NT PPTP V P N L A V P N V N P I n t e r n e t V P N 9.1 V P N Windows 98 Windows PPTP VPN Novell BorderManager T M I P s e c Wi n d o w s I n t e r n e t I S P I

More information

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas

目录 1 IPv6 快速转发 IPv6 快速转发配置命令 display ipv6 fast-forwarding aging-time display ipv6 fast-forwarding cache ipv6 fas 目录 1 IPv6 快速转发 1-1 1.1 IPv6 快速转发配置命令 1-1 1.1.1 display ipv6 fast-forwarding aging-time 1-1 1.1.2 display ipv6 fast-forwarding cache 1-1 1.1.3 ipv6 fast-forwarding aging-time 1-3 1.1.4 ipv6 fast-forwarding

More information

嵌入式系统实验报告之一

嵌入式系统实验报告之一 南京航空航天大学 嵌入式系统综合实验报告 Qtopia 在 S3C2440 开发板上的移植 040630520 彭立勋 2009.05 一 实验目的 1. 熟悉 ARM 体系结构 ; 2. 熟悉 Qtopia 图形环境 二 实验内容 将 Qtopia 图形环境移植到 FriendlyARM QQ2440 开发板 三 预备知识 Qtopia 的体系结构 四 实验设备及工具 硬件 :QQ2440 开发板

More information

untitled

untitled MPICH anzhulin@sohu.com 1 MPICH for Microsoft Windows 1.1 MPICH for Microsoft Windows Windows NT4/2000/XP Professional Server Windows 95/98 TCP/IP MPICH MS VC++ 6.x MS VC++.NET Compaq Visual Fortran 6.x

More information