Android GPS学习笔记(三)定位数据如何从GPS芯片到应用层


定位的基础知识

1、定位芯片和CPU之间通过串口进行通信
2、串口和CPU之间传输的是ASCII格式的NMEA(National Marine Electronics Association)信息,如:
[html]  view plain  copy
  1. $GPGGA,092204.999,4250.5589,S,14718.5084,E,1,04,24.4,19.7,M,,,,0000*1F  
  2. $GPGLL,4250.5589,S,14718.5084,E,092204.999,A*2D  
  3. $GPGSV,3,1,10,20,78,331,45,01,59,235,47,22,41,069,,13,32,252,45*70  
  4. $GPRMC,092204.999,A,4250.5589,S,14718.5084,E,0.00,89.68,211200,,*25  

基于以上两点,要探知定位数据从GPS芯片到应用层的流程,最好的途径就是从应用层输出NEMA信息的地方开始。

NMEA资料参见:卫星定位数据NMEA介绍

一、GPS定位的应用层实现

Luckily,在应用层我们可以通过onNmeaReceived()方法获取到NMEA信息,如下Code Fragment:

[java]  view plain  copy
  1. public class GpsTestActivity extends ActionBarActivity {  
  2.     /* Other Codes */  
  3.       
  4.     /** 获取系统的定位服务,记得在AndroidManifest中赋予定位方面的权限: 
  5.      * <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 
  6.      * <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/> 
  7.      * <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 
  8.      */  
  9.     LocationManager mLocationService = (LocationManager) getSystemService(Context.LOCATION_SERVICE);  
  10.     mLocationService.addNmeaListener(mNmeaListener);  
  11.       
  12.     private GpsStatus.NmeaListener mNmeaListener = new NmeaListener() {  
  13.         @Override  
  14.         public void onNmeaReceived(long timestamp, String nmea) {  
  15.             System.out.println(nmea + "\n");  
  16.         }  
  17.     };  
  18. }   

二、GPS定位的Framework层实现

GpsStatus.NmeaListener是一个接口类,来自GpsStatus.java文件:

[java]  view plain  copy
  1. frameworks\base\location\java\android\location\GpsStatus.java  
  2. /** 
  3.  * Used for receiving NMEA sentences from the GPS. 
  4.  * NMEA 0183 is a standard for communicating with marine electronic devices 
  5.  * and is a common method for receiving data from a GPS, typically over a serial port. 
  6.  * See <a href="http://en.wikipedia.org/wiki/NMEA_0183">NMEA 0183</a> for more details. 
  7.  * You can implement this interface and call {@link LocationManager#addNmeaListener} 
  8.  * to receive NMEA data from the GPS engine. 
  9.  */  
  10. public interface NmeaListener {  
  11.     void onNmeaReceived(long timestamp, String nmea);  
  12. }  
在上述App中,我们的应用程序实现了该方法,一旦NMEA数据到来,onNmeaReceived()方法就被调用一次,我们在Console上可以看到原始的NEMA信息。
那么接下来,就要寻找nmea数据的来源了。

mNmeaListener通过LocationManager类的addNmeaListener()方法进行注册(register):

[java]  view plain  copy
  1. frameworks\base\location\java\android\location\LocationManager.java  
  2. /** 
  3.  * Adds an NMEA listener. 
  4.  * 
  5.  * @param listener a {@link GpsStatus.NmeaListener} object to register 
  6.  * 
  7.  * @return true if the listener was successfully added 
  8.  * 
  9.  * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present 
  10.  */  
  11. public boolean addNmeaListener(GpsStatus.NmeaListener listener) {  
  12.     boolean result;  
  13.   
  14.     /* mNmeaListeners是LocationManager类的成员变量: 
  15.      * private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners = 
  16.      *      new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>(); 
  17.      */  
  18.     if (mNmeaListeners.get(listener) != null) {  
  19.         // listener is already registered  
  20.         return true;  
  21.     }  
  22.     try {  
  23.         GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);  
  24.         result = mService.addGpsStatusListener(transport);  
  25.         if (result) {  
  26.             mNmeaListeners.put(listener, transport);  
  27.         }  
  28.     } catch (RemoteException e) {  
  29.         Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);  
  30.         result = false;  
  31.     }  
  32.   
  33.     return result;  
  34. }  
这里,先检测定义的NmeaListener有没有被注册过,若果没有,注册之。
注册到哪里去了呢?
由mNmeaListeners成员的定义可知,和GpsStatus.NmeaListener进行关联的是GpsStatusListenerTransport,而它是LocationManager类的一个内部类。
只看相关的部分:

[java]  view plain  copy
  1. // This class is used to send GPS status events to the client's main thread.  
  2. private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {  
  3.     private final GpsStatus.NmeaListener mNmeaListener;  
  4.   
  5.     // This must not equal any of the GpsStatus event IDs  
  6.     private static final int NMEA_RECEIVED = 1000;  
  7.     private class Nmea {  
  8.         long mTimestamp;  
  9.         String mNmea;  
  10.   
  11.         Nmea(long timestamp, String nmea) {  
  12.             mTimestamp = timestamp;  
  13.             mNmea = nmea;  
  14.         }  
  15.     }  
  16.     private ArrayList<Nmea> mNmeaBuffer;  
  17.   
  18.     //G psStatusListenerTransport(GpsStatus.Listener listener){}   
  19.     GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {  
  20.         mNmeaListener = listener;  
  21.         mListener = null;  
  22.         mNmeaBuffer = new ArrayList<Nmea>();  
  23.     }  
  24.   
  25.     @Override  
  26.     public void onNmeaReceived(long timestamp, String nmea) {  
  27.         if (mNmeaListener != null) {  
  28.             synchronized (mNmeaBuffer) {  
  29.                 mNmeaBuffer.add(new Nmea(timestamp, nmea));  
  30.             }  
  31.             Message msg = Message.obtain();  
  32.             msg.what = NMEA_RECEIVED;  
  33.             // remove any NMEA_RECEIVED messages already in the queue  
  34.             mGpsHandler.removeMessages(NMEA_RECEIVED);  
  35.             mGpsHandler.sendMessage(msg);  
  36.         }  
  37.     }  
  38.   
  39.     private final Handler mGpsHandler = new Handler() {  
  40.         @Override  
  41.         public void handleMessage(Message msg) {  
  42.             if (msg.what == NMEA_RECEIVED) {  
  43.                 synchronized (mNmeaBuffer) {  
  44.                     int length = mNmeaBuffer.size();  
  45.                     for (int i = 0; i < length; i++) {  
  46.                         Nmea nmea = mNmeaBuffer.get(i);  
  47.                         mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);  
  48.                     }  
  49.                     mNmeaBuffer.clear();  
  50.                 }  
  51.             } else {  
  52.                 // synchronize on mGpsStatus to ensure the data is copied atomically.  
  53.                 }  
  54.             }  
  55.         }  
  56.     };  
  57. }  
在GpsStatusListenerTransport类中:
定义一个Nmea类型的链表mNmeaBuffer,一旦onNmeaReceived()接收到NMEA数据,新数据被加载到链表mNmeaBuffer中(mNmeaBuffer.add(new Nmea(timestamp, nmea))),然手置消息标志为NMEA_RECEIVED(msg.what = NMEA_RECEIVED)。
mGpsHandler对上述NMEA_RECEIVED消息进行处理,最终把传过来的NMEA数据发往应用层GpsTestActivity中的onNmeaReceived()。
那么,GpsStatusListenerTransport类中onNmeaReceived(long timestamp, String nmea)方法的nmea数据有谁提供呢?

GpsStatusListenerTransport类继承自IGpsStatusListener,由类前的字符"I"我们得知,它是一个扩展名为.aidl的文件。
注:
AIDL:AIDL机制用来完成在进程之间进行通信(在Android中不允许进程间共享数据),它的详细知识另外Google之。
这里,我们再次见到了onNmeaReceived():
[java]  view plain  copy
  1. rameworks\base\location\java\android\location\IGpsStatusListener.aidl  
  2. oneway interface IGpsStatusListener  
  3. {  
  4.     void onGpsStarted();  
  5.     void onGpsStopped();  
  6.     void onFirstFix(int ttff);  
  7.     void onSvStatusChanged(int svCount, in int[] prns, in float[] snrs, in float[] elevations, in float[] azimuths, int ephemerisMask, int almanacMask, int usedInFixMask);  
  8.     void onNmeaReceived(long timestamp, String nmea);  
  9. }  

oneway关键字是用来修饰远程调用行为。使用该关键词时,远程调用不是阻塞的,它只是发送事物数据并立即返回。接口的最终实现是把普通的远程调用按照Binder线程池的调用规则来接收,如果oneway是使用在本地调用上,那么不会有任何影响,并且调用依然是异步的。
下面,探究必须进入第三层。

三、GPS定位的Lib层实现

和IGpsStatusListener接头的是GpsLocationProvider类:

[java]  view plain  copy
  1. frameworks\base\services\java\com\android\server\location\GpsLocationProvider.java  
  2. public class GpsLocationProvider implements LocationProviderInterface {  
  3.     // 此处省略1000+N行  
  4.     private ArrayList<Listener> mListeners = new ArrayList<Listener>();  
  5.       
  6.     private final class Listener implements IBinder.DeathRecipient {  
  7.         final IGpsStatusListener mListener;  
  8.   
  9.         Listener(IGpsStatusListener listener) {  
  10.             mListener = listener;  
  11.         }  
  12.   
  13.         @Override  
  14.         public void binderDied() {  
  15.             if (DEBUG) Log.d(TAG, "GPS status listener died");  
  16.   
  17.             synchronized (mListeners) {  
  18.                 mListeners.remove(this);  
  19.             }  
  20.             if (mListener != null) {  
  21.                 mListener.asBinder().unlinkToDeath(this0);  
  22.             }  
  23.         }  
  24.     }  
  25.       
  26.     /** 
  27.      * called from native code to report NMEA data received 
  28.      */  
  29.     private void reportNmea(long timestamp) {  
  30.         synchronized (mListeners) {  
  31.             int size = mListeners.size();  
  32.             if (size > 0) {  
  33.                 // don't bother creating the String if we have no listeners  
  34.                 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);  
  35.                 String nmea = new String(mNmeaBuffer, 0, length);  
  36.   
  37.                 for (int i = 0; i < size; i++) {  
  38.                     Listener listener = mListeners.get(i);  
  39.                     try {  
  40.                         listener.mListener.onNmeaReceived(timestamp, nmea);  
  41.                     } catch (RemoteException e) {  
  42.                         Log.w(TAG, "RemoteException in reportNmea");  
  43.                         mListeners.remove(listener);  
  44.                         // adjust for size of list changing  
  45.                         size--;  
  46.                     }  
  47.                 }  
  48.             }  
  49.         }  
  50.     }  
  51. }  
GPS定位功能最终需要调用硬件实现,操作硬件就必须通过C/C++完成,GpsLocationProvider中包含许多native方法,采用JNI机制为上层提供服务。
在上面的Code Frame中,通过调用本地方法native_read_nmea()获取到NMEA数据,然后传数据到IGpsStatusListener接口类的onNmeaReceived()方法。
reportNmea()是被JNI方法回调的方法,在 JNI 的实现中,通过这些方法的回调来传递JNI层的执行结果。

源码编译出错,解决问题去。。。

native_read_nmea()在GpsLocationProvider类中定义:

[java]  view plain  copy
  1. private native int native_read_nmea(byte[] buffer, int bufferSize);  
native指明它是本地方法,和它对应的C/C++文件的实现是:
[cpp]  view plain  copy
  1. static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj, jbyteArray nmeaArray, jint buffer_size);  
How?Next...

[cpp]  view plain  copy
  1. frameworks\base\services\jni\com_android_server_location_GpsLocationProvider.cpp  
  2. static JNINativeMethod sMethods[] = {  
  3.     /* name, signature, funcPtr */  
  4.     /* other members... */  
  5.     {"native_read_nmea""([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},  
  6.     /* other members... */  
  7. };  
JNINativeMethod是Android中采用的Java和C/C++函数的映射方式,并在其中描述了函数的参数和返回值:

[cpp]  view plain  copy
  1. typedef struct {  
  2.     const char* name;       // Java文件中的本地方法  
  3.     const char* signature;  // 述了函数的参数和返回值  
  4.     void*       fnPtr;      // 指针,指向具体的C/C++函数  
  5. } JNINativeMethod;  
详细内容这里还是不展开了。
来看android_location_GpsLocationProvider_read_nmea()的实现:
[cpp]  view plain  copy
  1. static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj,  
  2.                                             jbyteArray nmeaArray, jint buffer_size)  
  3. {  
  4.     // this should only be called from within a call to reportNmea  
  5.     jbyte* nmea = (jbyte *)env->GetPrimitiveArrayCritical(nmeaArray, 0);  
  6.     int length = sNmeaStringLength;  
  7.     if (length > buffer_size)  
  8.         length = buffer_size;  
  9.     memcpy(nmea, sNmeaString, length);  
  10.     env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);  
  11.     return length;  
  12. }  
虽然不清楚JNI深入含义,但这个函数意思还是挺明显的,我们推断:
第5行:用来动态分配内存,nmea指向获取到的内存区域,同时把nmea和nmeaArray进行关联;
第6行:sNmeaStringLength指示一次从串口读取到的字节长度
第7、8行:在Java中调用native_read_nmea()方法时指明了我们需要取的数据长度,所以,如果从串口实际读取的数据长度大于我们需要的,我们对串口数据进行截取:即,只取指定长度的数据;
第9行:从串口读出的数据存在sNmeaString中,这里Copy到nmea指向的内存区域;
第10行:nmea指向的内存区域中的数据交给nmeaArray,然后释放nmea指向的内存空间。这里也可以看到,函数调用是通过nmeaArray传递NMEA数据的


下面应该看sNmeaStringLength、sNmeaString的设置过程:

[cpp]  view plain  copy
  1. static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)  
  2. {  
  3.     JNIEnv* env = AndroidRuntime::getJNIEnv();  
  4.     // The Java code will call back to read these values  
  5.     // We do this to avoid creating unnecessary String objects  
  6.     sNmeaString = nmea;  
  7.     sNmeaStringLength = length;  
  8.     env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);  
  9.     checkAndClearExceptionFromCallback(env, __FUNCTION__);  
  10. }  
method_reportNmea、、、有没有熟悉的感觉?
对,在GpsLocationProvider类中见过reportNmea(long timestamp)函数。

下面的代码片段表明,method_reportNmea()和reportNmea()是绑定在一起的,调用C/C++函数method_reportNmea,也就间接调用Java的reportNmea()方法。这中间的机制,就是JNI!

[cpp]  view plain  copy
  1. static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {  
  2.     /* other definitions... */  
  3.     method_reportNmea = env->GetMethodID(clazz, "reportNmea""(J)V");  
  4.     /* other definitions... */  
  5. }  
而method_reportNmea是在nmea_callback()函数中被调用的,哪里又调用nmea_callback()函数呢?
Let's go to neXt Layer...

四、GPS定位HAL层的实现

所谓Android的HAL层,也就是是Linux的应用程序。至于串口具体配置,比如寄存器配置、数据收发等芯片级实现,是在在Linux内核里的。

com_android_server_location_GpsLocationProvider.cpp文件中另外出现nmea_callback的地方是:

[cpp]  view plain  copy
  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.     request_utc_time_callback,  
  12. };  
GpsCallbacks结构体封装了所有需要回调的函数( 确切的说是函数指针 ),sGpsCallbacks调用关系:
[cpp]  view plain  copy
  1. static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)  
  2. {  
  3.     // this must be set before calling into the HAL library  
  4.     if (!mCallbacksObj)  
  5.         mCallbacksObj = env->NewGlobalRef(obj);  
  6.   
  7.     // fail if the main interface fails to initialize  
  8.     if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)  
  9.         return false;  
  10.   
  11.     /* other codes */  
  12.     return true;  
  13. }  
而android_location_GpsLocationProvider_init()在GpsLocationProvider类中调用native_init()时被调用:
[cpp]  view plain  copy
  1. static JNINativeMethod sMethods[] = {  
  2.      /* name, signature, funcPtr */  
  3.     {"native_init""()Z", (void*)android_location_GpsLocationProvider_init}  
  4. }  
[cpp]  view plain  copy
  1. 这里,我们找到了和上层的关系,和下层如何打交道呢?  
  2. 下面需要贴一大段代码:  
[cpp]  view plain  copy
  1. /** Represents the standard GPS interface. */  
  2. typedef struct {  
  3.     /** set to sizeof(GpsInterface) */  
  4.     size_t          size;  
  5.     /** 
  6.      * Opens the interface and provides the callback routines 
  7.      * to the implemenation of this interface. 
  8.      */  
  9.     int   (*init)( GpsCallbacks* callbacks );  
  10.     /** Starts navigating. */  
  11.     int   (*start)( void );  
  12.     /** Stops navigating. */  
  13.     int   (*stop)( void );  
  14.     /** Closes the interface. */  
  15.     void  (*cleanup)( void );  
  16.     /** Injects the current time. */  
  17.     int   (*inject_time)(GpsUtcTime time, int64_t timeReference,  
  18.                          int uncertainty);  
  19.     /** Injects current location from another location provider 
  20.      *  (typically cell ID). 
  21.      *  latitude and longitude are measured in degrees 
  22.      *  expected accuracy is measured in meters 
  23.      */  
  24.     int  (*inject_location)(double latitude, double longitude, float accuracy);  
  25.     /** 
  26.      * Specifies that the next call to start will not use the 
  27.      * information defined in the flags. GPS_DELETE_ALL is passed for 
  28.      * a cold start. 
  29.      */  
  30.     void  (*delete_aiding_data)(GpsAidingData flags);  
  31.     /** 
  32.      * min_interval represents the time between fixes in milliseconds. 
  33.      * preferred_accuracy represents the requested fix accuracy in meters. 
  34.      * preferred_time represents the requested time to first fix in milliseconds. 
  35.      */  
  36.     int   (*set_position_mode)(GpsPositionMode mode, GpsPositionRecurrence recurrence,  
  37.             uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time);  
  38.     /** Get a pointer to extension information. */  
  39.     const void* (*get_extension)(const char* name);  
  40. } GpsInterface;  
GpsInterface结构体封装了GPS实现的标准接口——接口,注意!接口不就时用来连接两端的吗?一端是com_android_server_location_GpsLocationProvider.cpp文件里的实现,那另一端就是。。。都探到这个地步了,另一端应该是串口方式直接和GPS芯片打交道的Linux驱动了吧?
确是,但是还需要一个媒介:
[cpp]  view plain  copy
  1. struct gps_device_t {  
  2.     struct hw_device_t common;  
  3.     /** 
  4.      * Set the provided lights to the provided values. 
  5.      * 
  6.      * Returns: 0 on succes, error code on failure. 
  7.      */  
  8.     const GpsInterface* (*get_gps_interface)(struct gps_device_t* dev);  
  9. };  
然后,
[cpp]  view plain  copy
  1. static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {  
  2.     int err;  
  3.     hw_module_t* module;  
  4.     /* other codes..*/  
  5.     err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);  
  6.     if (err == 0) {  
  7.         hw_device_t* device;  
  8.         err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);  
  9.         if (err == 0) {  
  10.             gps_device_t* gps_device = (gps_device_t *)device;  
  11.             sGpsInterface = gps_device->get_gps_interface(gps_device);  
  12.         }  
  13.     }  
  14.     /* other codes..*/  
  15. }  
  16. static JNINativeMethod sMethods[] = {  
  17.      /* name, signature, funcPtr */  
  18.     {"class_init_native""()V", (void *)android_location_GpsLocationProvider_class_init_native},  
  19. }  
GpsLocationProvider.java通过class_init_native的调用实现对C/C++文件中android_location_GpsLocationProvider_class_init_native的调用;
com_android_server_location_GpsLocationProvider.cpp通过gps_device_t获取操作GPS芯片的接口。How????
重点来了:GPS_HARDWARE_MODULE_ID
对,就是 GPS_HARDWARE_MODULE_ID
往下看:
[cpp]  view plain  copy
  1. ardware\qcom\gps\loc_api\libloc_api\gps.c  
  2. struct hw_module_t HAL_MODULE_INFO_SYM = {  
  3.     .tag = HARDWARE_MODULE_TAG,  
  4.     .version_major = 1,  
  5.     .version_minor = 0,  
  6.     .id = GPS_HARDWARE_MODULE_ID,  
  7.     .name = "loc_api GPS Module",  
  8.     .author = "Qualcomm USA, Inc.",  
  9.     .methods = &gps_module_methods,  
  10. };  
有木有?GPS_HARDWARE_MODULE_ID!
[cpp]  view plain  copy
  1. hardware\qcom\gps\loc_api\libloc_api\gps.c  
  2. extern const GpsInterface* gps_get_hardware_interface();  
  3.   
  4. const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)  
  5. {  
  6.     return gps_get_hardware_interface();  
  7.   
  8. }  
  9.   
  10. static int open_gps(const struct hw_module_t* module, char const* name,  
  11.         struct hw_device_t** device)  
  12. {  
  13.     struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));  
  14.     memset(dev, 0, sizeof(*dev));  
  15.   
  16.     dev->common.tag = HARDWARE_DEVICE_TAG;  
  17.     dev->common.version = 0;  
  18.     dev->common.module = (struct hw_module_t*)module;  
  19.     dev->get_gps_interface = gps__get_gps_interface;  
  20.   
  21.     *device = (struct hw_device_t*)dev;  
  22.     return 0;  
  23. }  
  24.   
  25. static struct hw_module_methods_t gps_module_methods = {  
  26.     .open = open_gps  
  27. };  
流程很清楚了:
gps_get_hardware_interface()函数在驱动程序中实现
    ——在gps__get_gps_interface()中被调用
        ——在open_gps()被调用
            ——在gps_module_methods中例化
                ——HAL_MODULE_INFO_SYM


const GpsInterface* gps_get_hardware_interface()函数在其他C文件实现,该C文件是和Linux驱动打交道的应用程序。基本功能:

1、open处理器CPU和GPS芯片连接的串口;

2、read串口NEMA数据,并解析;

3、根据上层传进来的回调函数,打包数据,调用相应Callback,进而发送到Android应用层。

[cpp]  view plain  copy
  1. static const GpsInterface  mGpsInterface = {  
  2.     .size =sizeof(GpsInterface),  
  3.     .init = gps_init,  
  4.         |--1、接收从上层传下来的GpsCallbacks变量,用它初始化GpsState->callbacks成员    
  5.         |--2、GpsState结构体的其他成员初始化  
  6.         |--3、GpsState->init状态设置为:STATE_INIT  
  7.         |--4、最重要:启动GPS线程,进行数据的读取、处理:  
  8.         state->thread = state->callbacks.create_thread_cb("gps", gps_state_thread, state);  
  9.             --gps_create_thread create_thread_cb;  
  10.                 --typedef pthread_t (* gps_create_thread)(const char* name, void (*start)(void *), void* arg);  
  11.                                   
  12.                                   
  13.     .start = gps_start,  
  14.         --设置GPS的状态为开始:GPS_STATUS_SESSION_BEGIN  
  15.     .stop = gps_stop,         
  16.         --设置GPS的状态为结束:GPS_STATUS_SESSION_END  
  17.     .cleanup = gps_cleanup,   
  18.         --退出需要进行的一些清理工作,如GpsState->init = STATE_QUIT,GpsCallbacks指针归null,信号量回收  
  19.     .inject_time = gps_inject_time,   
  20.         --可为空函数  
  21.     .inject_location = gps_inject_location,   
  22.         --可为空函数  
  23.     .delete_aiding_data = gps_delete_aiding_data,     
  24.         --可为空函数  
  25.     .set_position_mode = gps_set_position_mode,   
  26.         --设置GPS工作模式:单GPS、单BD、GPS/BD双系统  
  27.     .get_extension = gps_get_extension,   
  28.         --定位之外的扩展功能实现  
  29. };  
  30.   
  31. state->thread = state->callbacks.create_thread_cb("gps", gps_state_thread, state);                              
  32.     --static void gps_state_thread(void*  arg):  
  33.       1、state通过arg参数传入函数  
  34.       2、创建了Time和Nmea数据处理两个线程                                              
  35.         state->nmea_thread = state->callbacks.create_thread_cb("nmea_thread", gps_nmea_thread, state);  
  36.             --static void gps_nmea_thread(void*  arg)  
  37.                 --gps_opentty(state);  
  38.                    nmea_reader_init(reader);  
  39.                     --nmea_reader_parse(NmeaReader*  r) {  
  40.                         if (gps_state->callbacks.nmea_cb) {  
  41.                             struct timeval tv;  
  42.                             unsigned long long mytimems;  
  43.                             gettimeofday(&tv,NULL);  
  44.                             mytimems = tv.tv_sec * 1000 + tv.tv_usec / 1000;  
  45.                             gps_state->callbacks.nmea_cb(mytimems, r->in, r->pos);  
  46.                             D("reader_parse. %.*s ", r->pos, r->in );  
  47.                         }  
  48.                     }  

我们是从APP层NMEA信息输出自定向下分析的,APP层信息输出的最终起始是:gps_state->callbacks.nmea_cb(mytimems, r->in, r->pos);


到这里还有个问题:GPS芯片和CPU连接,使用的是哪个串口?这个串口号怎么确定的呢?

打算贴个完整HAL层的实例,考虑到代码很多,下篇在说吧。。

猜你喜欢

转载自blog.csdn.net/pashanhu6402/article/details/80366934