Android系统访问串口设备

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

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

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

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

  > 深入浅出 - 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 plain copy
  1. package cn.com.farsight.SerialService;  
  2. import java.io.BufferedReader;  
  3. import java.io.UnsupportedEncodingException;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.io.InputStreamReader;  
  7.   
  8. import android.util.Log;  
  9.   
  10. public class SerialService {  
  11.     private static final String TAG = "SerialService";  
  12.     // 底层初始化状态  
  13.     private boolean isInitOk = false;  
  14.   
  15.     // 加载本地库,read()和write()的实现通过JNI在本地代码实现  
  16.     static {  
  17.         Log.d(TAG, "System.loadLibrary()");  
  18.         System.loadLibrary("serial_runtime");  
  19.     }     
  20.       
  21.     // 构造器,用于初始化本地HAL及runtime  
  22.     public SerialService(){     
  23.         Log.d(TAG, "SerialService()");  
  24.         // 初始化本地HAL  
  25.         isInitOk =  _init();  
  26.         Log.d(TAG, "_init()");  
  27.     }  
  28.   
  29.     // 读串口数据  
  30.     public String read() {  
  31.         Log.d(TAG, "read()");  
  32.         if(!isInitOk)  
  33.             return "串口初始化失败,请确认已经连接串口设备。";  
  34.         // 由于 Java String是双字节字符,而串口数据是原始字节流,所以要进行转化  
  35.         byte[] data = new byte[128];  
  36.         // 从驱动读取字节流  
  37.         _read(data, 128);  
  38.            
  39.         String ret;  
  40.         try{  
  41.             // 转化为Java String字符  
  42.             ret = new String(data, "GBK");  
  43.         }catch(UnsupportedEncodingException e1) {  
  44.             return null;  
  45.         }  
  46.         return ret;  
  47.     }  
  48.   
  49.     // 写入字符串数据  
  50.     public int  write(String s) {  
  51.         Log.d(TAG, "write()");  
  52.         int len;  
  53.         try{  
  54.             // 将Java String字符串转码成字节流后,写入串口  
  55.             len = _write(s.getBytes("GBK"));  
  56.         }catch(UnsupportedEncodingException e1) {  
  57.             return -1;  
  58.         }  
  59.         return len;  
  60.     }  
  61.   
  62.     private static native boolean _init();  
  63.     private static native int _read(byte[] data, int len);  
  64.     private static native int _write(byte[] data);  
  65. }  

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

串口硬件抽象层头文件:

@serial_hal\include\serial.h

[cpp]  view plain copy
  1. #include <hardware/hardware.h>  
  2. #include <fcntl.h>  
  3. #include <errno.h>  
  4. #include <cutils/log.h>  
  5. #include <cutils/atomic.h>  
  6.   
  7. #define serial_HARDWARE_MODULE_ID "serial"  
  8.   
  9.   
  10. /*每一个硬件模块都每必须有一个名为HAL_MODULE_INFO_SYM的数据结构变量, 
  11. 它的第一个成员的类型必须为hw_module_t*/  
  12. struct serial_module_t {  
  13.     struct hw_module_t common; //模块类型  
  14.       
  15. };   
  16. /*见hardware.h中的hw_module_t定义的说明, 
  17. xxx_module_t的第一个成员必须是hw_module_t类型, 
  18. 其次才是模块的一此相关信息,当然也可以不定义, 
  19. 这里就没有定义模块相关信息 
  20. */  
  21.   
  22.   
  23. /*每一个设备数据结构的第一个成员函数必须是hw_device_t类型, 
  24. 其次才是各个公共方法和属性*/  
  25. struct serial_control_device_t {  
  26.     struct hw_device_t common; //设备类型  
  27.     /* supporting control APIs go here */  
  28.   
  29.     int (*serial_read_hal)(struct serial_control_device_t *dev, char *buf, int count);  
  30.     /***************************************/  
  31.     int (*serial_write_hal)(struct serial_control_device_t *dev, char *buf, int count);  
  32.     /***************************************/  
  33. };  
  34. /*见hardware.h中的hw_device_t的说明, 
  35. 要求自定义xxx_device_t的第一个成员必须是hw_device_t类型, 
  36. 其次才是其它的一些接口信息 
  37. */  

@serial_runtime\cn_com_farsight_SerialService_SerialService.cpp

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

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

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

[cpp]  view plain copy
  1. #include <hardware/hardware.h>  
  2. #include <fcntl.h>  
  3. #include <termios.h>  
  4. #include <errno.h>  
  5. #include <cutils/log.h>  
  6. #include <cutils/atomic.h>  
  7. #include <sys/ioctl.h>  
  8. #include <errno.h>  
  9. #include <string.h>  
  10. #include <dirent.h>  
  11. #include "../include/serial.h"  
  12.   
  13. int fd;  
  14.   
  15. static int serial_device_close(struct hw_device_t* device)  
  16. {  
  17.     LOGD("%s E", __func__);  
  18.     struct serial_control_device_t* ctx = (struct serial_control_device_t*)device;  
  19.     if (ctx) {  
  20.         free(ctx);  
  21.     }  
  22.     close(fd);  
  23.     LOGD("%s X", __func__);  
  24.     return 0;   
  25. }  
  26.   
  27. static int serial_read_drv(struct serial_control_device_t *dev, char *buf, int count)  
  28. {     
  29.     LOGD("%s E", __func__);  
  30.     int len = 0;  
  31.     len = read(fd, buf, count);  
  32.     if(len < 0)  
  33.     {  
  34.         perror("read");  
  35.     }  
  36.     LOGD("%s X", __func__);  
  37.     return len;  
  38. }  
  39.   
  40. static int serial_write_drv(struct serial_control_device_t *dev, char *buf, int size)  
  41. {     
  42.     LOGD("%s E", __func__);  
  43.     int len = write(fd, buf, size);  
  44.     if(len < 0)  
  45.     {  
  46.         perror("write");  
  47.     }  
  48.     LOGD("%s X", __func__);  
  49.     return len;  
  50. }  
  51.   
  52. static int serial_device_open(const struct hw_module_t* module, const char* name,  
  53.         struct hw_device_t** device)  
  54. {  
  55.     LOGD("%s E", __func__);  
  56.     struct serial_control_device_t *dev;  
  57.     struct termios opt;   
  58.   
  59.     dev = (struct serial_control_device_t *)malloc(sizeof(*dev));  
  60.     memset(dev, 0, sizeof(*dev));   
  61.   
  62.     //HAL must init property  
  63.     dev->common.tag= HARDWARE_DEVICE_TAG; //必须写这个  
  64.     dev->common.version = 0;  
  65.     dev->common.module= module;  
  66.   
  67.     dev->serial_read_hal = serial_read_drv;  
  68.   
  69.     dev->serial_write_hal = serial_write_drv;  
  70.     *device= &dev->common;  
  71.   
  72.     // MichaelTang add for open ttyUSBx   
  73.     char devname[PATH_MAX];  
  74.     DIR *dir;  
  75.     struct dirent *de;  
  76.     dir = opendir("/dev");  
  77.     if(dir == NULL)  
  78.         return -1;  
  79.     strcpy(devname, "/dev");  
  80.     char * filename = devname + strlen(devname);  
  81.     *filename++ = '/';  
  82.     while((de = readdir(dir))) {  
  83.         if(de->d_name[0] == '.' || strncmp(de->d_name, "ttyUSB", 6))        // start with . will ignor  
  84.             continue;  
  85.         strcpy(filename, de->d_name);  
  86.         if((fd = open(devname, O_RDWR | O_NOCTTY | O_NDELAY)) < 0)  
  87.         {         
  88.             LOGE("open error");  
  89.             return -1;  
  90.         }else {  
  91.             LOGD("open ok\n");  
  92.             break;  
  93.         }  
  94.     }  
  95.   
  96.   
  97.     //初始化串口  
  98.     tcgetattr(fd, &opt);  
  99.     //tcflush(fd, TCIOFLUSH);  
  100.     cfsetispeed(&opt, B9600);  
  101.     cfsetospeed(&opt, B9600);  
  102.   
  103.     //tcflush(fd, TCIOFLUSH);  
  104.   
  105.     opt.c_cflag |= (CLOCAL | CREAD);  
  106.   
  107.     opt.c_cflag &= ~CSIZE;  
  108.     opt.c_cflag &= ~CRTSCTS;  
  109.     opt.c_cflag |= CS8;  
  110.   
  111.     /*  
  112.        opt.c_cflag |= PARENB;  // enable; 允许输入奇偶校验 
  113.        opt.c_cflag |= PARODD;  // J check     对输入使用奇校验           
  114.        opt.c_iflag |= (INPCK | ISTRIP);  //  
  115.        */   
  116.     opt.c_iflag |= IGNPAR;  
  117.   
  118.     opt.c_cflag &= ~CSTOPB;  
  119.   
  120.     opt.c_oflag = 0;  
  121.     opt.c_lflag = 0;  
  122.   
  123.     tcsetattr(fd, TCSANOW, &opt);  
  124.   
  125.     LOGD("%s X", __func__);  
  126.   
  127.     return 0;  
  128. }  
  129.   
  130. //定一个hw_module_methods_t结构体,关联入口函数  
  131. static struct hw_module_methods_t serial_module_methods = {  
  132. open: serial_device_open    
  133. };  
  134.   
  135. //定义Stub入口  
  136. //注意必须使用:  
  137. //1。hw_module_t继承类  
  138. //2。必须使用HAL_MODULE_INFO_SYM这个名字  
  139.   
  140. const struct serial_module_t HAL_MODULE_INFO_SYM = {  
  141. common: {  
  142. tag: HARDWARE_MODULE_TAG,  
  143.      version_major: 1,  
  144.      version_minor: 0,  
  145.      id: serial_HARDWARE_MODULE_ID,   
  146.      //模块ID,上层的Service通过这个ID应用当前Stub  
  147.      name: "serial HAL module",  
  148.      author: "farsight",  
  149.      methods: &serial_module_methods, //入口函数管理结构体  
  150.     },   
  151.     /* supporting APIs go here */  
  152. };  


4. 相关代码下载:

http://download.csdn.net/detail/mr_raptor/7033385

你可能感兴趣的:(Android系统访问串口设备)