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

Android系统访问串口设备

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

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

  > 深入浅出 - Android系统移植与平台开发(一)- 初识HAL
http://blog.csdn.net/suofeng1234/article/details/51890847
  > 深入浅出 - Android系统移植与平台开发(二)- HAL
Stub框架分析

http://blog.csdn.net/suofeng1234/article/details/51890925

  > 深入浅出 - Android系统移植与平台开发(三) -
led HAL简单设计案例分析
http://blog.csdn.net/suofeng1234/article/details/51890944
1. 首先,我们先定义出串口的API类,即:SerialService,它为串口访问应用程序提示了两个API接口:read()和write()方法。

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

[java] view
plain copy

 





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
plain copy

 





#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介绍
http://blog.csdn.net/suofeng1234/article/details/51890944
[cpp] view
plain copy

 





#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

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