Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android系統訪問串口設備

Android系統訪問串口設備

編輯:關於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

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

#include 
#include 
#include 
#include 
#include 

#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/mr_raptor/article/details/8080606

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved