以前在android系统下怎样对硬件操作探讨了好久,因为android系统和LINUX系统有了很大的不同,对硬件操作比较麻烦。比如,文件系统的格式呀,打一个设备需要什么权限呀,总之很多问题。
在MINI6410的手册上提到有对硬件的操作,但资料很少,只知调用其中的函数,不知其然,这是非常痛苦的。已是我决定自己搞一个出来()。从界面到内核的流程:
界面:android---java编写
界面接口函数:
int Open(String deviceName);
int Write(int fd, in char[] writeBuf, int len);
int Read(int fd, out char[] readBuf, int len);
int Ioctl(int fd, int cmd, in long[] arg);
boolean Close(int fd);
JNI层:为界面提供接口,调用HAL层的代码
JNI层的接口函数:
static jint jni_open(JNIEnv *env, jobject thiz, jstring deviceName);
static jint jni_write(JNIEnv *env, jobject thiz, jint fd, jcharArray writeBuf, jint counts) ;
static jint jni_read(JNIEnv *env, jobject thiz, jint fd, jcharArray readBuf, jint counts) ;
static jint jni_ioctl(JNIEnv *env, jobject thiz, jint fd, jint cmd, jlongArray arg);
static jint jni_open(JNIEnv *env, jobject thiz, jstring deviceName);
static jboolean jni_close(JNIEnv *env, jobject thiz, jint fd) ;
HAL层:操作硬件
static int hal_write(char *write_buf, long buf_len);
static int hal_read(char *read_buf, long buf_len);
static int hal_ioctl(int cmd, long *arg);
static int hal_close();
最终 JNI层编译出一个.SO文件放到/system/lib下
HAL层编译出一个.SO文件放到/system/lib/hw下
接下来,在HAL层操作硬件就像在LINUX下操作硬件一样了,(回家的感觉),下面给出一段操作串的程序
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/times.h>
#include <sys/select.h>
#include <assert.h>
#include <sys/types.h>
#include <cutils/atomic.h>
#include <hardware/hardware.h>
#include <hardware/overlay.h>
#include "serial.h"
//串口相关
struct termios serial_oldtio;
struct termios serial_newtio;
fd_set read_fds;
/********************************************************************************
**函数名称:
**函数功能:
**函数参数:
**返 回 值:
**********************************************************************************/
static int set_serial_opts(int fd, int nSpeed, int nBits, char nEvent, int nStop)
{
int ret = -1;
if (fd < 0)
return -1;
//将目前终端机参数保存到结构体变量flydvd_oldtio中
if (tcgetattr(fd, &serial_oldtio) != 0)
{
//DLOGE("setupSerial");
goto fail;
}
//结构体serial_newtio清0
memset(&serial_newtio, 0, sizeof(serial_newtio));
//设置串口参数
serial_newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
serial_newtio.c_oflag &= ~OPOST;
serial_newtio.c_iflag &= ~(ICRNL | IGNCR);
serial_newtio.c_cflag |= CLOCAL | CREAD; //启动接收器
serial_newtio.c_cflag &= ~CSIZE;
serial_newtio.c_cc[VTIME] = 0;
serial_newtio.c_cc[VMIN] = 0;
serial_newtio.c_cc[VINTR] = 0;
serial_newtio.c_cc[VQUIT] = 0;
serial_newtio.c_cc[VERASE] = 0;
serial_newtio.c_cc[VKILL] = 0;
serial_newtio.c_cc[VEOF] = 0;
serial_newtio.c_cc[VTIME] = 1;
serial_newtio.c_cc[VMIN] = 0;
serial_newtio.c_cc[VSWTC] = 0;
serial_newtio.c_cc[VSTART] = 0;
serial_newtio.c_cc[VSTOP] = 0;
serial_newtio.c_cc[VSUSP] = 0;
serial_newtio.c_cc[VEOL] = 0;
serial_newtio.c_cc[VREPRINT] = 0;
serial_newtio.c_cc[VDISCARD] = 0;
serial_newtio.c_cc[VWERASE] = 0;
serial_newtio.c_cc[VLNEXT] = 0;
serial_newtio.c_cc[VEOL2] = 0;
switch (nBits)
{
case 7: serial_newtio.c_cflag |= CS7;break;
case 8: serial_newtio.c_cflag |= CS8;break;
default:
serial_newtio.c_cflag |= CS8;break;
}
switch (nEvent)
{
case 'O':
serial_newtio.c_cflag |= PARENB;
serial_newtio.c_cflag |= PARODD;
serial_newtio.c_iflag |= (INPCK|ISTRIP);
break;
case 'E':
serial_newtio.c_cflag |= PARENB;
serial_newtio.c_cflag &= ~PARODD;
serial_newtio.c_iflag |= (INPCK|ISTRIP);
break;
case 'N':
serial_newtio.c_cflag &= ~PARENB;
break;
default:
serial_newtio.c_cflag &= ~PARENB;
break;
}
switch (nSpeed)
{
case 9600:
cfsetispeed(&serial_newtio, B9600);
cfsetospeed(&serial_newtio, B9600);
break;
case 57600:
cfsetispeed(&serial_newtio, B57600);
cfsetospeed(&serial_newtio, B57600);
break;
case 115200:
cfsetispeed(&serial_newtio, B115200);
cfsetospeed(&serial_newtio, B115200);
break;
default:
cfsetispeed(&serial_newtio, B9600);
cfsetospeed(&serial_newtio, B9600);
break;
}
if (nStop == 1)
serial_newtio.c_cflag &= ~CSTOPB;
else if (nStop == 2)
serial_newtio.c_cflag = CSTOPB;
//刷新在串口中的输入输出数据
tcflush(fd, TCIFLUSH);
//设置当前的的串口参数为flydvd_newtio
if (tcsetattr(fd, TCSANOW, &serial_newtio) != 0)
{
//DLOGE("flydvd set error");
goto fail;
}
ret = 0;
fail:
return ret;
}
/********************************************************************************
**函数名称:
**函数功能:
**函数参数:
**返 回 值:
**********************************************************************************/
int serial_write(int fd, unsigned char *buf, int len)
{
int ret = -1;
if (fd < 0)
return ret;
//写入数据
ret = write(fd, buf, len);
if (ret > 0)
{
//DLOGI("flydvd_write OK");
}
else
{
//DLOGE("flydvd_write error");
}
return ret;
}
/********************************************************************************
**函数名称:
**函数功能:
**函数参数:
**返 回 值:
**********************************************************************************/
long serial_read(int fd, unsigned char *buf, int len)
{
long ret = -1;
struct timeval tv_timeout;
FD_SET(fd, &read_fds);
tv_timeout.tv_sec = 1;
tv_timeout.tv_usec = 0;
switch (select(fd+1, &read_fds, NULL, NULL, &tv_timeout))
{
case -1:
//DLOGE("select error");
break;
case 0:
//DLOGE("select timeout");
break;
default:
if (FD_ISSET(fd, &read_fds))
{
//读取数据
ret = read(fd, buf, len);
/*
if (ret > 0)
{
//DLOGD("DVD read %d bytes:", ret);
//for (i=0; i<ret; i++)
//{
//DLOGD("%02X", read_buf);
//}
return ret;
}
else
{
return -1;
//continue;
//DLOGD("flydvd not data to read ret is :%d", ret);
}
*/
}
break;
}
return ret;
}
/********************************************************************************
**函数名称:
**函数功能:
**函数参数:
**返 回 值:
**********************************************************************************/
int serial_open(void)
{
int fd = -1;
int res = 0;
pthread_t thread_id;
fd = open("/dev/ttyS0",O_RDWR | O_NOCTTY | O_NDELAY);
if (fd > 0)
{
//DLOGI("flydvd com open OK");
if (set_serial_opts(fd, 115200, 8, 'N', 1) == -1)
{
//DLOGE("set com opts error");
return -1;
}
FD_ZERO(&read_fds);
}
return fd;
}
/********************************************************************************
**函数名称:
**函数功能:
**函数参数:
**返 回 值:
**********************************************************************************/
int serial_close(int fd)
{
if (fd < 0)
return -1;
//恢复旧的端口参数
tcsetattr(fd, TCSANOW, &serial_oldtio);
//关闭串口
if (!close(fd))
{
//DLOGI("flydvd_close ok");
return 0;
}
return -1;
}
看看,是不是和LINUX下操作一个串口一样呢!!
当然,我这个工程比较大,代码量很大,不能一一给大家展示,在此只能给大家一个思路,让大家从中了解原理