您的位置:首页 > 移动开发 > Android开发

Android串口通信访问

2015-08-12 16:54 423 查看
在常见的嵌入式外设中,串口通信是经常使用的一种通信机制,本篇文章给你带来,如何在Android系统中实现对串口设备的访问。

在Android中如何访问底层Linux的设备驱动,必然要用到HAL,即:硬件抽象层。关于HAL的概念及框架分析,请查看作者的下面几篇博文。

> 深入浅出 - Android系统移植与平台开发(七)- 初识HAL

/article/1354937.html

> 深入浅出 - Android系统移植与平台开发(八)- HAL
Stub框架分析

http://blog.csdn.net/mr_raptor/article/details/8074549

> 深入浅出 - Android系统移植与平台开发(十) -
led HAL简单设计案例分析

http://blog.csdn.net/mr_raptor/article/details/8082360

1. 首先,我们先定义出串口的API类,即:SerialService,它为串口访问应用程序提示了两个API接口:read()和write()方法。

@serial_app\src\cn\com\farsight\SerialService\SerialService.java

[java] view
plaincopy





package cn.com.farsight.SerialService;

import java.io.BufferedReader;

import java.io.UnsupportedEncodingException;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;



import android.util.Log;



public class SerialService {

private static final String TAG = "SerialService";

// 底层初始化状态

private boolean isInitOk = false;



// 加载本地库,read()和write()的实现通过JNI在本地代码实现

static {

Log.d(TAG, "System.loadLibrary()");

System.loadLibrary("serial_runtime");

}



// 构造器,用于初始化本地HAL及runtime

public SerialService(){

Log.d(TAG, "SerialService()");

// 初始化本地HAL

isInitOk = _init();

Log.d(TAG, "_init()");

}



// 读串口数据

public String read() {

Log.d(TAG, "read()");

if(!isInitOk)

return "串口初始化失败,请确认已经连接串口设备。";

// 由于 Java String是双字节字符,而串口数据是原始字节流,所以要进行转化

byte[] data = new byte[128];

// 从驱动读取字节流

_read(data, 128);



String ret;

try{

// 转化为Java String字符

ret = new String(data, "GBK");

}catch(UnsupportedEncodingException e1) {

return null;

}

return ret;

}



// 写入字符串数据

public int write(String s) {

Log.d(TAG, "write()");

int len;

try{

// 将Java String字符串转码成字节流后,写入串口

len = _write(s.getBytes("GBK"));

}catch(UnsupportedEncodingException e1) {

return -1;

}

return len;

}



private static native boolean _init();

private static native int _read(byte[] data, int len);

private static native int _write(byte[] data);

}

2. 编写SerialService的运行时代码,即:cn_com_farsight_SerialService_SerialService.cpp,实现JNI调用函数:_init(),_read(),_write()。

串口硬件抽象层头文件:

@serial_hal\include\serial.h

[cpp] view
plaincopy





#include <hardware/hardware.h>

#include <fcntl.h>

#include <errno.h>

#include <cutils/log.h>

#include <cutils/atomic.h>



#define serial_HARDWARE_MODULE_ID "serial"





/*每一个硬件模块都每必须有一个名为HAL_MODULE_INFO_SYM的数据结构变量,

它的第一个成员的类型必须为hw_module_t*/

struct serial_module_t {

struct hw_module_t common; //模块类型



};

/*见hardware.h中的hw_module_t定义的说明,

xxx_module_t的第一个成员必须是hw_module_t类型,

其次才是模块的一此相关信息,当然也可以不定义,

这里就没有定义模块相关信息

*/





/*每一个设备数据结构的第一个成员函数必须是hw_device_t类型,

其次才是各个公共方法和属性*/

struct serial_control_device_t {

struct hw_device_t common; //设备类型

/* supporting control APIs go here */



int (*serial_read_hal)(struct serial_control_device_t *dev, char *buf, int count);

/***************************************/

int (*serial_write_hal)(struct serial_control_device_t *dev, char *buf, int count);

/***************************************/

};

/*见hardware.h中的hw_device_t的说明,

要求自定义xxx_device_t的第一个成员必须是hw_device_t类型,

其次才是其它的一些接口信息

*/

@serial_runtime\cn_com_farsight_SerialService_SerialService.cpp

下面的代码用到JNI部分知识点,详情请看:

> 深入浅出 - Android系统移植与平台开发(九)- JNI介绍

/article/1354935.html

[cpp] view
plaincopy





#include <hardware/hardware.h>

#include <fcntl.h>

#include <termios.h>

#include <errno.h>

#include <cutils/log.h>

#include <cutils/atomic.h>

#include <sys/ioctl.h>

#include <errno.h>

#include <string.h>

#include <dirent.h>

#include "../include/serial.h"



int fd;



static int serial_device_close(struct hw_device_t* device)

{

LOGD("%s E", __func__);

struct serial_control_device_t* ctx = (struct serial_control_device_t*)device;

if (ctx) {

free(ctx);

}

close(fd);

LOGD("%s X", __func__);

return 0;

}



static int serial_read_drv(struct serial_control_device_t *dev, char *buf, int count)

{

LOGD("%s E", __func__);

int len = 0;

len = read(fd, buf, count);

if(len < 0)

{

perror("read");

}

LOGD("%s X", __func__);

return len;

}



static int serial_write_drv(struct serial_control_device_t *dev, char *buf, int size)

{

LOGD("%s E", __func__);

int len = write(fd, buf, size);

if(len < 0)

{

perror("write");

}

LOGD("%s X", __func__);

return len;

}



static int serial_device_open(const struct hw_module_t* module, const char* name,

struct hw_device_t** device)

{

LOGD("%s E", __func__);

struct serial_control_device_t *dev;

struct termios opt;



dev = (struct serial_control_device_t *)malloc(sizeof(*dev));

memset(dev, 0, sizeof(*dev));



//HAL must init property

dev->common.tag= HARDWARE_DEVICE_TAG; //必须写这个

dev->common.version = 0;

dev->common.module= module;



dev->serial_read_hal = serial_read_drv;



dev->serial_write_hal = serial_write_drv;

*device= &dev->common;



// MichaelTang add for open ttyUSBx

char devname[PATH_MAX];

DIR *dir;

struct dirent *de;

dir = opendir("/dev");

if(dir == NULL)

return -1;

strcpy(devname, "/dev");

char * filename = devname + strlen(devname);

*filename++ = '/';

while((de = readdir(dir))) {

if(de->d_name[0] == '.' || strncmp(de->d_name, "ttyUSB", 6)) // start with . will ignor

continue;

strcpy(filename, de->d_name);

if((fd = open(devname, O_RDWR | O_NOCTTY | O_NDELAY)) < 0)

{

LOGE("open error");

return -1;

}else {

LOGD("open ok\n");

break;

}

}





//初始化串口

tcgetattr(fd, &opt);

//tcflush(fd, TCIOFLUSH);

cfsetispeed(&opt, B9600);

cfsetospeed(&opt, B9600);



//tcflush(fd, TCIOFLUSH);



opt.c_cflag |= (CLOCAL | CREAD);



opt.c_cflag &= ~CSIZE;

opt.c_cflag &= ~CRTSCTS;

opt.c_cflag |= CS8;



/*

opt.c_cflag |= PARENB; // enable; 允许输入奇偶校验

opt.c_cflag |= PARODD; // J check 对输入使用奇校验

opt.c_iflag |= (INPCK | ISTRIP); //

*/

opt.c_iflag |= IGNPAR;



opt.c_cflag &= ~CSTOPB;



opt.c_oflag = 0;

opt.c_lflag = 0;



tcsetattr(fd, TCSANOW, &opt);



LOGD("%s X", __func__);



return 0;

}



//定一个hw_module_methods_t结构体,关联入口函数

static struct hw_module_methods_t serial_module_methods = {

open: serial_device_open

};



//定义Stub入口

//注意必须使用:

//1。hw_module_t继承类

//2。必须使用HAL_MODULE_INFO_SYM这个名字



const struct serial_module_t HAL_MODULE_INFO_SYM = {

common: {

tag: HARDWARE_MODULE_TAG,

version_major: 1,

version_minor: 0,

id: serial_HARDWARE_MODULE_ID,

//模块ID,上层的Service通过这个ID应用当前Stub

name: "serial HAL module",

author: "farsight",

methods: &serial_module_methods, //入口函数管理结构体

},

/* supporting APIs go here */

};

4. 相关代码下载:

http://download.csdn.net/detail/mr_raptor/7033385
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: