編輯:關於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); }
串口硬件抽象層頭文件:
@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
首先需要先介紹下LayoutAnimationController: * 1.LayoutAnimationController用於為一個layo
結構 繼承關系 public abstract class AsyncTask extends Object java.lang.Object andr
ListView下刷新刷功能相信從事Android開發的猿友們並不陌生,包括現在Google親兒子SwipeRefreshLayout實現效果在一些APP上也能看見(不過
1.界面設置默認的 Android Studio 為灰色界面,可以選擇使用炫酷的黑色界面。Settings --> Appearance --> Theme