Android系统访问串口设备

论坛 期权论坛 编程之家     
选择匿名的用户   2021-5-24 06:02   27   0

在常见的嵌入式外设中,串口通信是经常使用的一种通信机制,本篇文章给你带来,如何在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
在CODE上查看代码片 派生到我的代码片
  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. import android.util.Log;
  8. public class SerialService {
  9. private static final String TAG = "SerialService";
  10. // 底层初始化状态
  11. private boolean isInitOk = false;
  12. // 加载本地库,read()和write()的实现通过JNI在本地代码实现
  13. static {
  14. Log.d(TAG, "System.loadLibrary()");
  15. System.loadLibrary("serial_runtime");
  16. }
  17. // 构造器,用于初始化本地HAL及runtime
  18. public SerialService(){
  19. Log.d(TAG, "SerialService()");
  20. // 初始化本地HAL
  21. isInitOk = _init();
  22. Log.d(TAG, "_init()");
  23. }
  24. // 读串口数据
  25. public String read() {
  26. Log.d(TAG, "read()");
  27. if(!isInitOk)
  28. return "串口初始化失败,请确认已经连接串口设备。";
  29. // 由于 Java String是双字节字符,而串口数据是原始字节流,所以要进行转化
  30. byte[] data = new byte[128];
  31. // 从驱动读取字节流
  32. _read(data, 128);
  33. String ret;
  34. try{
  35. // 转化为Java String字符
  36. ret = new String(data, "GBK");
  37. }catch(UnsupportedEncodingException e1) {
  38. return null;
  39. }
  40. return ret;
  41. }
  42. // 写入字符串数据
  43. public int write(String s) {
  44. Log.d(TAG, "write()");
  45. int len;
  46. try{
  47. // 将Java String字符串转码成字节流后,写入串口
  48. len = _write(s.getBytes("GBK"));
  49. }catch(UnsupportedEncodingException e1) {
  50. return -1;
  51. }
  52. return len;
  53. }
  54. private static native boolean _init();
  55. private static native int _read(byte[] data, int len);
  56. private static native int _write(byte[] data);
  57. }

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

串口硬件抽象层头文件:

@serial_hal\include\serial.h

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

@serial_runtime\cn_com_farsight_SerialService_SerialService.cpp

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

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

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

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


4. 相关代码下载:

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

转载至:http://blog.csdn.net/mr_raptor/article/details/21161389

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP