现在的位置: 首页 > 综合 > 正文

porting gps to android2.3 (一)

2013年06月13日 ⁄ 综合 ⁄ 共 5477字 ⁄ 字号 评论关闭

        最近刚好有机会移植一款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交互口的

static const GpsInterface* get_gps_interface() {
    int err;
    hw_module_t* module;
    const GpsInterface* interface = NULL;
    err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);//frankBIBI获取模块
    if (err == 0) {//frankBIBI
        hw_device_t* device;
        err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);//获取设备
      if (err == 0) {///frankBIBI
//,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
           gps_device_t* gps_device = (gps_device_t *)device;
            interface = gps_device->get_gps_interface(gps_device);//--frankBIBI 获取交互接口          
 // interface = gps_get_interface();
        }
    }

    return interface;
}

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

//frankBIBI
static int open_XXgps(const struct hw_module_t* module, char const* name,
        struct hw_device_t** device)
{
    struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
    memset(dev, 0, sizeof(*dev));

    dev->common.tag = HARDWARE_DEVICE_TAG;
    dev->common.version = 0;
    dev->common.module = (struct hw_module_t*)module;
    dev->common.close = (int (*)(struct hw_device_t*))close_lights;
    dev->get_gps_interface = gps_get_hardware_interface;//交互
    *device = (struct hw_device_t*)dev;
    return 0;
}


static struct hw_module_methods_t gps_module_methods = {
    .open = open_XXgps
};

const struct hw_module_t HAL_MODULE_INFO_SYM = {
    .tag = HARDWARE_MODULE_TAG,
    .version_major = 1,
    .version_minor = 0,
    .id = GPS_HARDWARE_MODULE_ID,
    .name = "XX GPS Module",
    .author = "The Android Open Source Project",
    .methods = &gps_module_methods,
};
//.......................................................................

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

这样应用就明白了吧,很类似流接口吧
static const GpsInterface  XXGpsInterface = {
    XX_gps_init,
    XX_gps_start,
    XX_gps_stop,
    XX_gps_set_fix_frequency,
    XX_gps_cleanup,
    XX_gps_inject_time,
    XX_gps_delete_aiding_data,
    XX_gps_set_position_mode,
    XX_gps_get_extension,
};

const GpsInterface* gps_get_hardware_interface()
{
    return &XXGpsInterface;
}

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

 

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

这是为什么呢?

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

static void
nmea_reader_set_callback( NmeaReader*  r, gps_location_callback  cb )
{
    r->callback = cb;
    if (cb != NULL && r->fix.flags != 0) {
        D("%s: sending latest fix to new callback", __FUNCTION__);
        r->callback( &r->fix );
        r->fix.flags = 0;
    }
}

 

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

       else if (cmd == CMD_START) {
                        if (!started) {
                            D("gps thread starting  location_cb=%p", state->callbacks.location_cb);
                            started = 1;
  
                       nmea_reader_set_callback( reader, state->callbacks.location_cb );//frankBIBI
 
                            state->init = STATE_START;

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

/** GPS callback structure. */
typedef struct {
    /** set to sizeof(GpsCallbacks) */
    size_t      size;
    gps_location_callback location_cb;
    gps_status_callback status_cb;
    gps_sv_status_callback sv_status_cb;
    gps_nmea_callback nmea_cb;
    gps_set_capabilities set_capabilities_cb;
    gps_acquire_wakelock acquire_wakelock_cb;
    gps_release_wakelock release_wakelock_cb;
    gps_create_thread create_thread_cb;
} GpsCallbacks;

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

为什么呢?

GPS.h中给我们提示

/** Callback with location information.
 *  Can only be called from a thread created by create_thread_cb.
 */
typedef void (* gps_location_callback)(GpsLocation* location);

/** Callback with status information.
 *  Can only be called from a thread created by create_thread_cb.
 */
typedef void (* gps_status_callback)(GpsStatus* status);

/** Callback with SV status information.
 *  Can only be called from a thread created by create_thread_cb.
 */
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来创建我们要的线程!

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

GpsCallbacks sGpsCallbacks = {
    sizeof(GpsCallbacks),
    location_callback,
    status_callback,
    sv_status_callback,
    nmea_callback,
    set_capabilities_callback,
    acquire_wakelock_callback,
    release_wakelock_callback,
    create_thread_callback,
};

 

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

GpsCallbacks sGpsCallbacks = {
    sizeof(GpsCallbacks),
    location_callback,
    status_callback,
    sv_status_callback,
    nmea_callback,
    set_capabilities_callback,
    acquire_wakelock_callback,
    release_wakelock_callback,
    create_thread_callback,
};

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

我们的硬件适配层就先到这里了。

--------------------------希望有错误,请指点,谢谢.

 

 

 

 

 

         

     

抱歉!评论已关闭.