中科微北斗HAL层代码学习
1.功能:在GpsLocationProvider类构建时调用class_init_native(),根据加载gps.default.so(也就是中科微的HAL层)
从串口读北斗芯片NMEA数据,并解析再提供给GpsLocationProvider.
//GpsLocationProvider类装载时执行静态语句块,静态语句块和静态变量时平级,先定义先执行
GpsLocationProvider.java(frameworks\base\services\java\com\android\server\location)
static {
class_init_native();
}
com_android_server_location_GpsLocationProvider.cpp (frameworks\base\services\jni)
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native}, //JNI和JAVA函数方法对应表
....省略
}
static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
int err;
hw_module_t* module;
err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); //加载gps.default.so
if (err == 0) {
hw_device_t* device;
err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device); //执行HAL的open函数
if (err == 0) {
gps_device_t* gps_device = (gps_device_t *)device;
sGpsInterface = gps_device->get_gps_interface(gps_device); //得到HAL层接口。Java调用JNI接口在调用HAL接口
}
}
....省略
}
1.socket 通信和epoll多个I/O并发操作处理
static void gps_state_init( GpsState* state)
{
state->control[0] = -1; //在这里control[0]负责发送
state->control[1] = -1; //control[1]负责接收
/*********************************************************************************************************************
socketpair()函数用于创建一对无名的、相互连接的套接子。
如果函数成功,则返回0,创建好的套接字分别是sv[0]和sv[1];否则返回-1,错误码保存于errno中。
基本用法:
1. 这对套接字可以用于全双工通信,每一个套接字既可以读也可以写。例如,可以往sv[0]中写,从sv[1]中读;或者从sv[1]中写,从sv[0]中读;
2. 如果往一个套接字(如sv[0])中写入后,再从该套接字读时会阻塞,只能在另一个套接字中(sv[1])上读成功;
*********************************************************************************************************************/
if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, state->control ) < 0 ) { //创建两个套件字,用两个套接字直接通信
D("could not create thread control socket pair: %s", strerror(errno));
goto Fail;
}
....省略
}
实例1:
static int epoll_register( int epoll_fd, int fd )
{
struct epoll_event ev;
int ret, flags;
/* important: make the fd non-blocking */
flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_NONBLOCK); //添加I/O非阻塞操作,不管读到没有读到,都会马上返回释放端口
ev.events = EPOLLIN; //触发事件的条件,有可读,比如北斗芯片往串口里写数据,串口有数据可读,就会触发事件
ev.data.fd = fd;
do {
ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev ); //把文件描述符添加到epoll队列中进行管理
} while (ret < 0 && errno == EINTR);
return ret;
}
static void gps_state_thread( void* arg )
{
int epoll_fd = epoll_create(2); //创建两个epoll
int control_fd = state->control[1]; //control[1]负责接收control[0]消息
// register control file descriptors for polling
epoll_register( epoll_fd, control_fd ); //把>control[1]添加到epoll进行管理,见实例1
epoll_register( epoll_fd, gps_fd ); //把串口设备的文件描述符添加到epoll进行管理,见实例1
// now loop
for (;;) {
struct epoll_event events[2];
int ne, nevents;
//没有事件产生就在这阻塞,可以同时处理两个文件事件并发,等待EPOLLIN事件
nevents = epoll_wait( epoll_fd, events, 2, -1 );
if (nevents < 0) {
if (errno != EINTR)
D("epoll_wait() unexpected error: %s", strerror(errno));
continue;
}
#if NMEA_DEBUG
D("gps thread received %d events", nevents);
#endif
for (ne = 0; ne < nevents; ne++) {
if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
D("EPOLLERR or EPOLLHUP after epoll_wait() !?");
return;
}
if ((events[ne].events & EPOLLIN) != 0) { //两个文件I/O有数据可读
int fd = events[ne].data.fd;
if (fd == control_fd) //socket control[1]套接字事件
{
....省略
} else if (fd == gps_fd) { //串口设备的事件
....省略
}
}
....省略
}
}
socket操作:
static void gps_state_start( GpsState* s )
{
char cmd = CMD_START;
int ret;
do {
ret=write( s->control[0], &cmd, 1 ); //写cmd到control[0],epoll检测control[1]
}
while (ret < 0 && errno == EINTR);
....省略
}