android 深度搜索学习笔记一 (单词统计)

第一章 第一个linux驱动程序 单词统计

编写linux驱动程序的步骤

  建立linux驱动骨架 :module_init module_exit    

  注册和注销设备文件:misc_register  misc_deregister

  指定与驱动相关的信息

  指定回调函数

  编写业务逻辑

  编写makefile文件

  编译linux驱动程序

  安装和卸载linux驱动程序

统计单词个数驱动程序

 Word_count.c文件内容如下:

#include <linux/module.h>

#include <linux/init.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/miscdevice.h>

#include <asm/uaccess.h>

 

//定义设备文件名

#define DEVICE_NAME "wordcount"

//保存向设备文件写入的数据

static unsigned char mem[10000];

//单词数

static int word_count = 0;

#define TRUE 255

#define FALSE 0

 

//检查字符是否为空格

static unsigned char is_spacewhite(char c)

{

if (c == 32 || c == 9 || c == 13 || c == 10)

return TRUE;

else

return FALSE;

}

//统计单词数

static int get_word_count(const char *buf)

{

int n = 1;

int i = 0;

char c = ' ';

 

char flag = 0; // 处理多个空格分隔的情况,0:正常情况,1:已遇到一个空格

if (*buf == '\0')

return 0;

//  1个字符是空格,从0开始计数

if (is_spacewhite(*buf) == TRUE)

n--;

 

//  扫描字符串中的每一个字符

for (; (c = *(buf + i)) != '\0'; i++)

{

//  只由一个空格分隔单词的情况

if (flag == 1 && is_spacewhite(c) == FALSE)

{

 

flag = 0;

}

//  由多个空格分隔单词的情况,忽略多余的空格

else if (flag == 1 && is_spacewhite(c) == TRUE)

{

 

continue;

}

//  当前字符为空格是单词数加1

if (is_spacewhite(c) == TRUE)

{

n++;

flag = 1;

}

}

//  如果字符串以一个或多个空格结尾,不计数(单词数减1

if (is_spacewhite(*(buf + i - 1)) == TRUE)

n--;

return n;

}

 

//从设备文件读取数据

//file:指向设备文件

//buf:保存可读取的数据

//count:可读取的字节数

//ppos:读取数据的偏移量

static ssize_t word_count_read(struct file *file,char __user *buf,size_t count,loff_t *ppos){

unsigned char temp[4];

 

temp[0] = word_count >> 24;

temp[1] = word_count >> 16;   

temp[2] = word_count >> 8;

temp[3] = word_count;

if (copy_to_user(buf, (void*) temp, 4))

{

return -EINVAL;

}

printk("read:word count:%d", (int) count);

 

return count;

 

}

//向设备文件写入数据

//file:指向设备文件

//buf:保存写入的数据

//count:写入数据的字节数

//ppos:写入数据的偏移量

static ssize_t word_count_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos){

size_t written=count;

//将用户空间的数据,复制到内核空间

if(copy_from_user(mem,buf,count)){

return -EINVAL;

}

mem[count]="\0";

//统计单词个数

word_count=get_word_count(mem);

//输出已写入的字节数

printk("written count:%d",(int)word_count);

return written;

}

//描述与设备文件触发的事件对应的回设函数指针

//owner:设备事件回调函数应用于哪此驱动模块

//指定调用的函数

static struct file_operations dev_fops={

.owner= THIS_MODULE,

.read=word_count_read,

.write=word_count_write

};

//描述设备文件的信息

//minor:指定次设备号,此处是动态生成

//name:设备文件名称

static struct miscdevice misc={

.minor=MISC_DYNAMIC_MINOR,

.name=DEVICE_NAME,

.fops=&dev_fops

};

//初始化linux驱动

static int word_count_init(void){

int ret;

//建立设备文件

ret=misc_register(&misc);

 

//输出日志信息

printk("word_count_init_success\n");

return ret;

}

//退出linux驱动

static void word_count_exit(void){

misc_deregister(&misc);

printk("word_count_init_exit_sucess\n");

}

//注册初始化linux驱动的函数

module_init(word_count_init);

//注册退出linux驱动的函数

module_exit(word_count_exit);

 

//指定驱动的相关信息

//模块作者

MODULE_AUTHOR ("retacn_yue");

//模块描述

MODULE_DESCRIPTION("statistics of word count.");

//模块别名

MODULE_ALIAS("word count module.");

//开源协议

MODULE_LICENSE("GPL");

 

在主机linux环境下运行

编写makefile文件

ifneq ($(KERNELRELEASE),)

obj-m :=word_count.o

else

#KERNELDIR=/usr/src/kernels/2.6.35.14-106.fc14.i686/

KERNELDIR=/usr/src/linux-headers-3.2.0-29-generic

PWD :=$(shell pwd)

all:

make -C $(KERNELDIR) M=$(PWD)

clean:

rm -rf *.ko *.o *.mod.c *.mod.o *.symvers *.order

endif

 

 Make编译程序

root@vm:/opt/linux/driver/word_count# make

make -C /usr/src/linux-headers-3.2.0-29-generic M=/opt/linux/driver/word_count

make[1]: 正在进入目录 `/usr/src/linux-headers-3.2.0-29-generic'

  LD      /opt/linux/driver/word_count/built-in.o

  CC [M]  /opt/linux/driver/word_count/word_count.o

  Building modules, stage 2.

  MODPOST 1 modules

  CC      /opt/linux/driver/word_count/word_count.mod.o

  LD [M]  /opt/linux/driver/word_count/word_count.ko

make[1]:正在离开目录 `/usr/src/linux-headers-3.2.0-29-generic'

 

会以当前目录生成.ko的库文件

在主机安装驱动程序测试

#安装linux驱动

root@vm:/opt/linux/driver/word_count# insmod word_count.ko 

#查看是否安装成功

root@vm:/opt/linux/driver/word_count# lsmod | grep word_count

word_count             20942  0 

#查看驱动输出的日志信息

root@vm:/opt/linux/driver/word_count# dmesg | grep word_count | tail -n 2

[ 1917.206964] word_count_init_success

 

 

 

编写在linux下的测试程序test_word_count.c示例代码如下:

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

int main(int argc, char *argv[])

{

int testdev;

unsigned char buf[4];

 

testdev = open("/dev/wordcount", O_RDWR);

if (testdev == -1)

{

printf("Cann't open file \n");

return 0;

}

if (argc > 1)

{

 

write(testdev, argv[1], strlen(argv[1]));

printf("string:%s\n", argv[1]);

}

 

read(testdev, buf, 4);

 

int n = 0;

//  4个字节还原成int类型的值

n = ((int) buf[0]) << 24 | ((int) buf[1]) << 16 | ((int) buf[2]) << 8

        | ((int) buf[3]);

printf("word byte display:%d,%d,%d,%d\n", buf[0], buf[1], buf[2], buf[3]);

printf("word count:%d\n", n);

close(testdev);

return 0;

}

 

 

 

 

编译程序:

root@vm:/opt/linux/driver/word_count# gcc test_word_count.c -o test_word_count

root@vm:/opt/linux/driver/word_count# ls

built-in.o    modules.order      word_count_book.c  word_count.mod.o

linux_test    Module.symvers     word_count.c       word_count.o

Makefile      test_word_count    word_count.ko

Makefile_arm  test_word_count.c  word_count.mod.c

 

 

查看dev中的目录设备

crw-------  1 root root     10,  55  8月  8 10:51 wordcount

可以看出主设备号 为10,是简单字符设备

    Misc_register只能设置次设备号

查看当前系统中的主设备和主设备号

root@vm:/opt/linux/driver/word_count# cat /proc/devices 

Character devices:

  1 mem

  4 /dev/vc/0

  4 tty

  4 ttyS

  5 /dev/tty

  5 /dev/console

  5 /dev/ptmx

  5 ttyprintk

  6 lp

  7 vcs

 10 misc

 13 input

 

测试驱动程序

root@vm:/opt/linux/driver/word_count# ./test_word_count "hello retacn"

string:hello retacn

word byte display:0,0,0,2

word count:2

卸载驱动程序

root@vm:/opt/linux/driver/word_count# rmmod word_count

 

查看模块信息

root@vm:/opt/linux/driver/word_count# modinfo word_count.ko 

filename:       word_count.ko

license:        GPL

alias:          word count module.

description:    statistics of word count.

author:         retacn_yue

srcversion:     2CD81D366F7598BAB6C1384

depends:        

vermagic:       3.2.0-29-generic SMP mod_unload modversions 

 

开源协议

GPL 强迫使用该开源协议的软件开源

LGPL 通类库引用的方式使用LGPL类库,不需要开源软件的代码

BSD 可以自由修改可开源,也可不开源

Appach licence 2.0 协议 同 BSD协议

MIT协议 同BSD 作者只保留版权

 

 

注册注销设备文件

Extern int misc_register(struct miscdevice * misc);

Extern int misc_deregister(struct miscdevice * misc);

 

指定回调函数

fileoperation中指定回调函数

内核空间和用户空间的数据互访 copy_to_user  copy_from_user

 

 

 

编写编译角本

可以在ubuntu linux  mini6410开发板和android模拟器上测试单词统计驱动

 

Common.sh角本文件内容如下:

#ubuntu内核目录

UBUNTU_KERNEL_PATH=/usr/src/linux-headers-3.2.0-29-generic

#开发板linux内核目录

 6410_KERNEL_PATH=/opt/kernel/linux-2.6.38

#开发板android内核目录

S3C6410_ANDROID_KERNEL_PATH=/opt/kernel/linux-2.6.36-android

 

#android源码

OK6410_ANDROID_SRC_PATH=/opt/kernel/Android-2.3.4

S3C6410_ANDROID_SRC_PATH=/opt/kernel/Android-2.3.4

 

#设定交叉编译工具链路径

export PATH=$PATH:/opt/FriendlyARM/toolschain/4.5.1/bin

 

selected_device=""  #  "":无可用Android设备

selected_target=1  #  选择目标,  1: ubuntu linux  2: Android设备

 

#选择目标设力备

function select_target()

{

    echo "1Ubuntu Linux"

    echo "2MINI6410开发板"

    echo "3Android模拟器"

    read -p "请选择要在那类设备上运行(1" selected_target

    if [ "$selected_target" == "" ]; then

       selected_target=1

    fi

}

 

#查找android设备

function find_devices()

{

device_list=$(adb devices)

        

        if [ "${device_list:0:4}" != "List" ]; then

    device_list=$(adb devices)

    if [ "${device_list:0:4}" != "List" ]; then

exit

            fi

        fi

value=$(echo $device_list | cut -d' ' -f5)

if [ "$value" == "" ]; then

    echo "无可用Android设备"

else

            selected_device=$value   # 假设只有1个设备

    value=$(echo $device_list | cut -d' ' -f7)

 

    #  多个设备

    if [ "$value" != "" ]; then

       i=5

       index=1

       value="~~~"

       echo "可用设备列表"

       while [ "" == "" ]

       do          

  value=$(echo $device_list | cut -d' ' -f$i)

  let "i=$i+2"

  if [ "$value" == "" ]; then

      break;

  fi

  echo "$index: $value"

  let "index=$index+1"

       done       

       read -p "您想选择哪个Android设备?请输入序号(1)" number

       if [ "$number" == "" ]; then

   number=1

       fi

       let "number=3 + $number * 2"

       selected_device=$(echo $device_list | cut -d' ' -f$number)

    fi

fi

}

 

 

Build.sh内容如下

source /opt/driver/common.sh

select_target

if [ $selected_target ==1 ]; then

source ./build_ubuntu.sh

elif [ $selected_target ==2 ]; then

source ./build_mini6410.sh

elif [ $selected_target == 3 ]; then

source ./build_emulater.sh

Fi

 

 

build_ubuntu.sh  文件内容如下:

#build_ubuntu.sh     

source /opt/linux/driver/common.sh 

make   -C  $UBUNTU_KERNEL_PATH  M=${PWD}

testing=$(lsmod | grep  "word_count")

if [ "$testing" != "" ]; then

    rmmod word_count

fi

insmod ${PWD}/word_count.ko

 

#build_mini6410.sh文件内容如下:#build_mini6410.sh

source /opt/linux/driver/common.sh

#make -C $MINI6410_KERNEL_PATH M=${PWD}

make -C $MINI6410_ANDROID_KERNEL_PATH M=${PWD}

find_devices

if [ "$selected_device" == "" ]; then

exit

else

adb -s $selected_device push ${PWD}/word_count.ko /data/local 

testing=$(adb -s $selected_device shell lsmod | grep "word_count")

if [ "$testing" != "" ]; then

adb -s $selected_device shell rmmod word_count

fi

adb -s $selected_device shell "insmod /data/local/word_count.ko"

adb -s $selected_device shell "chmod 777 /dev/wordcount"

fi

 

 

编译 安装 卸载linux驱动

查看日志输出信息和驱动模块信息

root@vm:/opt/linux/driver/word_count# dmesg  | tail -n 1

[10256.765760] word_count_init_success

root@vm:/opt/linux/driver/word_count# modinfo word_count.ko

filename:       word_count.ko

license:        GPL

alias:          word count module.

description:    statistics of word count.

author:         retacn_yue

srcversion:     2CD81D366F7598BAB6C1384

depends:        

vermagic:       2.6.29-g46b05b2-dirty mod_unload modversions ARMv7 

root@vm:/opt/linux/driver/word_count#

 

安装linux驱动命令 insmod modprobe ,两者的区别的modprobe可以检查模块的依赖性

在使用modprobe安装驱动前,要先使用depmod命令检测linux驱动模块的依赖关系

 

测试linux驱动

使用ubuntu linux测试驱动程序

可以使用如下命令进行测试:

root@vm:/opt/linux/driver/word_count# echo 'hello retacn yue' > /dev/wordcount

root@vm:/opt/linux/driver/word_count# dmesg

.....

[  148.327839] hub 2-2:1.0: unable to enumerate USB device on port 2

[10128.904880] word_count_init_success

[10224.430495] word_count_init_exit_sucess

[10224.432402] word_count_init_success

[10256.763563] word_count_init_exit_sucess

[10256.765760] word_count_init_success

[13319.946934] written count:3

编写测试程序

#include <stdio.h>

#include <fcntl.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

int main(int argc, char *argv[])

{

int testdev;  //打开设备文件的句柄

unsigned char buf[4]; //表示单词个数的四个字节

//打开设备文件

testdev = open("/dev/wordcount", O_RDWR);

//打开文件失败,输出错误信息

if (testdev == -1)

{

printf("Cann't open file \n");

return 0;

}

if (argc > 1)

{

//向设备文件写入待统计的字符串

write(testdev, argv[1], strlen(argv[1]));

printf("string:%s\n", argv[1]);

}

//读取设备文失件中的单词数

read(testdev, buf, 4);

 

int n = 0;

//  4个字节还原成int类型的值

n = ((int) buf[0]) << 24 | ((int) buf[1]) << 16 | ((int) buf[2]) << 8

        | ((int) buf[3]);

//输出从设备文件获取的四个字节的值

printf("word byte display:%d,%d,%d,%d\n", buf[0], buf[1], buf[2], buf[3]);

//输出统计的单词数

printf("word count:%d\n", n);

//关闭设备文件

close(testdev);

return 0;

}

 

编译执行程序

//编译程序

root@vm:/opt/linux/driver/word_count# gcc test_word_count.c -o test_word_count

//没有命令行参数时

root@vm:/opt/linux/driver/word_count# test_word_count 

word byte display:0,0,0,3

word count:3

//有命令行参数时

root@vm:/opt/linux/driver/word_count# test_word_count "hell retacn yue test"

string:hell retacn yue test

word byte display:0,0,0,4

word count:4

 

 

android模拟器上使用原生c代码进行测试驱动程序

在使用androidlinux内核进行编译时需要进行设置,内核默认不允许动态加载linux驱动,

在编译内核之前要进行如下配置:

 [*] Enable loadable module support  ---> 选中前三项,重新编译内核

mini6410 编译内核的方式进行

使用编译好的内核创建模拟器,也可直接将系统烧写到开发板进行测试

此处使用的的在将内核烧写到开发板后进行测试

/ # echo 'hello retacn yue' > /dev/wordcount

/ # dmesg

//可以看到如下运行结果

<4>word_count_init_success

<6>request_suspend_state: wakeup (0->0) at 1889525693085 (2000-10-30 03:22:13.088438257 UTC)

<4>word_count_init_exit_sucess

<4>word_count_init_success

<4>written count:3/ #

 

 

使用test_word_count.c测试程序进行测试

编写android.mk文件,文件内容如下:

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

#指定要编译的源代码文件

LOCAL_SRC_FILES := test_word_count.c

#指定模块名,也就是编译后生成的可执行文件名

LOCAL_MODULE :=test_word_count

#指定在什么模式下编译,optional是在任何模式下都可以编译

#可以设置的模式有:

#user 限制用户对android系统的访问,适用于发布产品 

#userdebug 类似于user模式,但有root权限

#eng 一般在开发过程中设置该模式,有重多调试工具

#optional 

LOCAL_MODULE_TAGS :=optional

#表示建立可执行文件

#静态库文件为BUILD_STATIC_LIBRARY

#动态库文件为BUILD_SDARED_LIBRARY

include $(BUILD_EXECUTABLE)

 

交叉编译测试程序(android源码编译不成功)

可以将word_count目录复制到android源码目录下

也可以在android源码目录中为word_count建立一个符号链接

这里我们使用第二种方式,android源码目录中建立一个符号链接,命令如下:

root@vm:/opt/linux/driver/word_count# ln -s /opt/linux/driver/word_count/ /opt/kernel/Android-2.3.4/development

此时查看android源码目录下的development目录下会生成word_count目录的一个符号链接

初始化编译命令:

root@vm:/opt/kernel/Android-2.3.4# source ./build/envsetup.sh

 

编译程序的方法有两种:

一 进入~/word_count目录执行 mm命令

二 在根目下执行mmm命令

编译成功后可以在 /out/target/product/generic/system/bin下找到编译后的文件

 

将文件上传到开发板,未完成(源码未编译成功????????)

 

使用android NDK测试linux驱动程序,示例代码如下:

 

package cn.yue.android.word.count.ndk;

 

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.EditText;

import android.widget.TextView;

import android.widget.Toast;

import android.app.Activity;

 

/**

 * linux驱动单词统计

 * 

 * ndk测试程序

 * 

 * @version

 * 

 * @Description:

 * 

 * @author <a href="mailto:zhenhuayue@sina.com">Retacn</a>

 * 

 * @since 2014-10-21

 * 

 */

public class MainActivity extends Activity implements OnClickListener {

/* 要写入的字符串内容 */

private EditText edt_write_word;

/* 显示单词个数 */

private TextView txt_word_count;

 

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

findView();

}

 

/**

 * 实例化控件

 */

private void findView() {

edt_write_word = (EditText) this.findViewById(R.id.edt_write_word);

txt_word_count = (TextView) this.findViewById(R.id.txt_read_wrod);

// 从设备文件读出单词个数

this.findViewById(R.id.btn_read).setOnClickListener(this);

// 向设备文件写入字符串

this.findViewById(R.id.btn_write).setOnClickListener(this);

 

}

 

@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.btn_read:// 读取单词个数

txt_word_count.setText("单词数为: " + String.valueOf(readWordCountFromDev()));

Toast.makeText(MainActivity.this, readWordCountFromDev()+"", Toast.LENGTH_SHORT).show();

break;

case R.id.btn_write:// 向设备写入字符串

writeStringToDev(edt_write_word.getText().toString());

Toast.makeText(MainActivity.this, "已向/dev/word_count写入字符串"+edt_write_word.getText().toString(), Toast.LENGTH_SHORT).show();

break;

}

}

 

// 本地方法

public native int readWordCountFromDev();

 

public native void writeStringToDev(String str);

 

static {

System.loadLibrary("ndk_test_word_count");

}

}

 

 

#include <string.h>

#include <jni.h>

#include <fcntl.h>

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

#include <stdlib.h>

 

jint Java_cn_yue_android_word_count_ndk_MainActivity_readWordCountFromDev(

JNIEnv* env, jobject thiz) {

 

int dev;

jint wordcount = 0;

unsigned char buf[4];

 

dev = open("/dev/wordcount", O_RDONLY);

 

read(dev, buf, 4);

 

int n = 0;

n = ((int) buf[0]) << 24 | ((int) buf[1]) << 16 | ((int) buf[2]) << 8

| ((int) buf[3]);

wordcount = (jint) n;

close(dev);

return wordcount;

}

char* jstring_to_pchar(JNIEnv* env, jstring str) {

char* pstr = NULL;

jclass clsstring = (*env)->FindClass(env, "java/lang/String");

jstring strencode = (*env)->NewStringUTF(env, "utf-8");

jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes",

"(Ljava/lang/String;)[B");

jbyteArray byteArray = (jbyteArray)(

(*env)->CallObjectMethod(env, str, mid, strencode));

jsize size = (*env)->GetArrayLength(env, byteArray);

jbyte* pbyte = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE);

if (size > 0) {

pstr = (char*) malloc(size);

memcpy(pstr, pbyte, size);

}

return pstr;

}

void Java_cn_yue_android_word_count_ndk_MainActivity_writeStringToDev(

JNIEnv* env, jobject thiz, jstring str) {

 

int dev;

dev = open("/dev/wordcount", O_WRONLY);

char* pstr = jstring_to_pchar(env, str);

if (pstr != NULL) {

write(dev, pstr, strlen(pstr));

}

close(dev);

}

 

直接使用java代码测试 略

 

将驱动编译进linux内核进行测试

将动驱程序编译进android系统的linux内核进行测试

Aword_count.c放到linux内核代码中

 root@vm:/opt/linux/driver/word_count# cp word_count.c /opt/kernel/linux-2.6.36-android/drivers/char

修改kconfig文件,endmenu前添加如下代码:

config WORD_COUNT    //word_count驱动模块的变量名为CONFIG_WROD_COUNT

bool "word_count_driver"   //表示该驱动只参有两项设置

help              //设置菜单项的帮助信息

this is a word count driver. It can get a word count from /dev/word_count

Endmenu

修改makefile文件,添加如下内容

obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o

obj-$(CONFIG_MOXA_SMARTIO) += mxser.o

obj-$(CONFIG_COMPUTONE) += ip2/

obj-$(CONFIG_WORD_COUNT)+= word_count.o

obj-$(CONFIG_RISCOM8) += riscom8.o

obj-$(CONFIG_ISI) += isicom.o

 

设置.config文件,可以通过make menuconfig来进行配置

Device Drivers  --->  Character devices  --->  [*] word_count_driver 

打开.config文件可以看到该项设置为y

CONFIG_WORD_COUNT=y

 

编译linux内核 

Make

烧写到开发板进行测试

/ # chmod 777 /dev/wordcount 

/ # echo "hello" >/dev/wordcount

/ # dmesg

可以看到如下内容

<4>written count:1written count:2

 

使用eclipse开发和测试linux驱动程序(linuxeclipse创建c工程有问题 ?需要重新安装cdt作测试)

建立c工程  

File--->new--->other--->c project--->next--->工程名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值