porting gps to android2.3

来源:互联网 发布:模拟法庭教学软件 编辑:程序博客网 时间:2024/05/16 05:02
最近刚好有机会移植一款GPS到我们的产品上,就GPS模块移植本身而言,是很简单的。做过WINCE 或PC开发GPS的朋友肯定很清楚了,无非就是把GPS的标准数据从串口读出来,然后解析,应用程序获取其中经纬度,定位时间等信息,根据自己的需求或转化成地图上具体地点,或做其它使用。

       先来说说一般的硬GPS,其优点不言而喻,相对“基站定位”,其精度要高很多,特别是在基站信号差的地方。缺点是往往第1次冷启动的时间慢的蛋疼!,还有天线的问题,我记得很明显,在室外我测试GPS,下午的时候信号特别好(估计卫星刚好在我头上),晚上就特别差,真郁闷- -!以前我们同事也做过GPS,但是效果都不好。射频部分的电路处理也非常不专业。这也是一般硬GPS的我认为最大的缺点了。

       现有出现了一种AGPS的方案,说实话,我还没实现这个功能。android2.3GPS接口部分,可以参见gps.h。AGPS的作用一是能有效解决第1次冷启动慢的问题(一般通过网络预先下载星率表)。2是在室内等穿透力很弱的地方,AGPS也能过利用基站辅助定位。

       好了,本文介绍的GPS的移植过程,AGPS我还等待大家帮忙了。

      我的使用环境是android2.3,GPS与2.2类似,但也有比较大的区别,特别是JNI和SO硬件适配层。这里我记录下,在写动态库的时候遇到的两个主要问题。

 

     1,JNI层调用我们的动态库,这里我们可以参见代码自己的模拟器gps_qemu.c文件

           主要注意的是:

        com_android_server_location_GpsLocationProvider.cpp中,当我们通过在开机启动gps服务的时候,我们最开始是需要通过JNI调用GPS交互口的

  1. static const GpsInterface* get_gps_interface() {  
  2.     int err;  
  3.     hw_module_t* module;  
  4.     const GpsInterface* interface = NULL;  
  5.     err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);//frankBIBI获取模块  
  6.     if (err == 0) {//frankBIBI  
  7.         hw_device_t* device;  
  8.         err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);//获取设备  
  9.       if (err == 0) {///frankBIBI  
  10. //,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,  
  11.            gps_device_t* gps_device = (gps_device_t *)device;  
  12.             interface = gps_device->get_gps_interface(gps_device);//--frankBIBI 获取交互接口            
  1.  // interface = gps_get_interface();  
  2.         }  
  3.     }  
  4.   
  5.     return interface;  
  6. }  


对应的我们的libgps.so需要这么配合使用才能正确调用

  1. //frankBIBI  
  1. static int open_XXgps(const struct hw_module_t* module, char const* name,  
  2.         struct hw_device_t** device)  
  3. {  
  4.     struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));  
  5.     memset(dev, 0, sizeof(*dev));  
  6.   
  7.     dev->common.tag = HARDWARE_DEVICE_TAG;  
  8.     dev->common.version = 0;  
  9.     dev->common.module = (struct hw_module_t*)module;  
  10.     dev->common.close = (int (*)(struct hw_device_t*))close_lights;  
  11.     <strong>dev->get_gps_interface = gps_get_hardware_interface;//交互</strong>  
  1.     *device = (struct hw_device_t*)dev;  
  2.     return 0;  
  3. }  
  4.   
  5.   
  6. static struct hw_module_methods_t gps_module_methods = {  
  7.     .open = open_XXgps  
  8. };  
  9.   
  10. const struct hw_module_t HAL_MODULE_INFO_SYM = {  
  11.     .tag = HARDWARE_MODULE_TAG,  
  12.     .version_major = 1,  
  13.     .version_minor = 0,  
  14.     .id = GPS_HARDWARE_MODULE_ID,  
  15.     .name = "XX GPS Module",  
  16.     .author = "The Android Open Source Project",  
  17.     .methods = &gps_module_methods,  
  18. };  
  19. //.......................................................................  

重点是这个dev->get_gps_interface = gps_get_hardware_interface;//交互
 

  1. 这样应用就明白了吧,很类似流接口吧  
  1. static const GpsInterface  XXGpsInterface = {  
  2.     XX_gps_init,  
  3.     XX_gps_start,  
  4.     XX_gps_stop,  
  5.     XX_gps_set_fix_frequency,  
  6.     XX_gps_cleanup,  
  7.     XX_gps_inject_time,  
  8.     XX_gps_delete_aiding_data,  
  9.     XX_gps_set_position_mode,  
  10.     XX_gps_get_extension,  
  11. };  
  12.   
  13. const GpsInterface* gps_get_hardware_interface()  
  14. {  
  15.     return &XXGpsInterface;  
  16. }  


这样交互就OK了。接下来,主要就是初始化,GPS启动,数据采集,数据解析,数据返回到JNI了。

 

2,这里讲一下,遇到的第2个问题。就是初始化完后,数据返回到JNI层,出现了libgps.so崩溃的问题。我相信,第1次在android2.3下面调试gps的同学很多会遇到。

这是为什么呢?

具体错误我是再这个函数中遇到的

  1. static void  
  2. nmea_reader_set_callback( NmeaReader*  r, gps_location_callback  cb )  
  3. {  
  4.     r->callback = cb;  
  5.     if (cb != NULL && r->fix.flags != 0) {  
  6.         D("%s: sending latest fix to new callback", __FUNCTION__);  
  7.         <strong>r->callback( &r->fix );</strong>  
  8.         r->fix.flags = 0;  
  9.     }  
  10. }  

 

调用它的函数是gps_state_thread线程函数,作用是检测通道是否有控制命令或数据,然后做相应的控制。

  1. else if (cmd == CMD_START) {  
  2.                  if (!started) {  
  3.                      D("gps thread starting  location_cb=%p", state->callbacks.location_cb);  
  4.                      started = 1;  
  5.   
  6.                 <u><strong>nmea_reader_set_callback( reader, state->callbacks.location_cb );//frankBIBI</strong></u>  
  7.   
  8.                      state->init = STATE_START;  

还有有点模糊么,好吧,我们把回调函数的接口放出(GPS.H)

  1. /** GPS callback structure. */  
  2. typedef struct {  
  3.     /** set to sizeof(GpsCallbacks) */  
  4.     size_t      size;  
  5.    <em><strong><u> gps_location_callback location_cb;</u></strong></em>  
  6.     gps_status_callback status_cb;  
  7.     gps_sv_status_callback sv_status_cb;  
  8.     gps_nmea_callback nmea_cb;  
  9.     gps_set_capabilities set_capabilities_cb;  
  10.     gps_acquire_wakelock acquire_wakelock_cb;  
  11.     gps_release_wakelock release_wakelock_cb;  
  12.     gps_create_thread create_thread_cb;  
  13. } GpsCallbacks;  


好了r->callback( &r->fix );往JNI返回数据了。这里就出现了LIBGPS.SO崩溃了...崩溃的画面类似我前一篇文章“3G开关”那个画面类似。

为什么呢?

GPS.h中给我们提示

  1. /** Callback with location information. 
  2.  *  Can only be called from a thread created by create_thread_cb. 
  3.  */  
  4. typedef void (* gps_location_callback)(GpsLocation* location);  
  5.   
  6. /** Callback with status information. 
  7.  *  Can only be called from a thread created by create_thread_cb. 
  8.  */  
  9. typedef void (* gps_status_callback)(GpsStatus* status);  
  10.   
  11. /** Callback with SV status information. 
  12.  *  Can only be called from a thread created by create_thread_cb. 
  13.  */  
  14. typedef void (* gps_sv_status_callback)(GpsSvStatus* sv_info);  

在来看我们是怎么创建我们的gps_state_thread,在gps_state_init函数中创建线程。

pthread_create( &state->thread, NULL, gps_state_thread, state ) != 0

 

很明显,其无法与JNI层的反馈函数想联系。OK  ,我们就利用JNI中注册的create_thread_cb来创建我们要的线程!

  1. //frankBIBI   
  1. if (state->callbacks.create_thread_cb( &state->thread, gps_state_thread, state )==0) {  
  2.         LOGE("could not create gps thread: %s", strerror(errno));  
  3.         goto Fail;  
  1.    
  1. //相应的初始化的地方要调整s->callbacks = *callbacks要提前  
  1. XX_gps_init(GpsCallbacks* <strong>callbacks</strong>)//  
  1. {  
  2.     GpsState*  s = _gps_state;  
  3. //frankBIBI  
  4. s->callbacks = *callbacks  
  1. if (!s->init)//         
  1. gps_state_init(s);  
  2.    if (s->fd < 0)  
  3.        return -1;  
  4.  //  s->callbacks = *callbacks  
  1. return 0;  

关于GpsCallbacks* callbacks......callback  解释如下:

当我们在做GPS初始化的时候,com_android_server_location_GpsLocationProvider.cpp中的static const GpsInterface* GetGpsInterface(JNIEnv* env, jobject obj)函数中“ if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) ”将sGpsCallbacks这个反馈函数的结构体传入到我们的LIBGPS.SO初始化注册!!

  1. GpsCallbacks sGpsCallbacks = {  
  2.     sizeof(GpsCallbacks),  
  3.     location_callback,  
  4.     status_callback,  
  5.     sv_status_callback,  
  6.     nmea_callback,  
  7.     set_capabilities_callback,  
  8.     acquire_wakelock_callback,  
  9.     release_wakelock_callback,  
  10.     create_thread_callback,  
  11. };  

 

好了,libgps.so主要遇到就这两个问题。这样你就可以通过

  1. GpsCallbacks sGpsCallbacks = {  
  2.     sizeof(GpsCallbacks),  
  3.     location_callback,  
  4.     status_callback,  
  5.     sv_status_callback,  
  6.     nmea_callback,  
  7.     set_capabilities_callback,  
  8.     acquire_wakelock_callback,  
  9.     release_wakelock_callback,  
  10.     create_thread_callback,  
  11. };  

利用这些回调函数,数据和信息都可以通过这些返回给JNI,来填充GPS接口数据。其它部分参照源码自带的模拟器就可以完成。


原创粉丝点击