原址:http://blog.csdn.net/u013686019/article/details/47444839
写在前面

在漫长的Android源码编译等待过程中,想起之前写过一部分的Android定位实现的探究小品,于是继续探究。

:代码都是片段化的代码,用来提纲挈领的说明问题。

定位的基础知识
1、定位芯片和CPU之间通过串口进行通信
2、串口和CPU之间传输的是ASCII格式的NMEA(National Marine Electronics Association)信息,如:

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

二、GPS定位的Framework层实现

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

[java] view plaincopy print?
  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 plaincopy print?
  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. /* mNmeaListeners是LocationManager类的成员变量:
  14. * private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
  15. *      new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>();
  16. */
  17. if (mNmeaListeners.get(listener) != null) {
  18. // listener is already registered
  19. return true;
  20. }
  21. try {
  22. GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
  23. result = mService.addGpsStatusListener(transport);
  24. if (result) {
  25. mNmeaListeners.put(listener, transport);
  26. }
  27. } catch (RemoteException e) {
  28. Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
  29. result = false;
  30. }
  31. return result;
  32. }

这里,先检测定义的NmeaListener有没有被注册过,若果没有,注册之。
注册到哪里去了呢?
由mNmeaListeners成员的定义可知,和GpsStatus.NmeaListener进行关联的是GpsStatusListenerTransport,而它是LocationManager类的一个内部类。
只看相关的部分:

[java] view plaincopy print?
  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. // This must not equal any of the GpsStatus event IDs
  5. private static final int NMEA_RECEIVED = 1000;
  6. private class Nmea {
  7. long mTimestamp;
  8. String mNmea;
  9. Nmea(long timestamp, String nmea) {
  10. mTimestamp = timestamp;
  11. mNmea = nmea;
  12. }
  13. }
  14. private ArrayList<Nmea> mNmeaBuffer;
  15. //G psStatusListenerTransport(GpsStatus.Listener listener){}
  16. GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
  17. mNmeaListener = listener;
  18. mListener = null;
  19. mNmeaBuffer = new ArrayList<Nmea>();
  20. }
  21. @Override
  22. public void onNmeaReceived(long timestamp, String nmea) {
  23. if (mNmeaListener != null) {
  24. synchronized (mNmeaBuffer) {
  25. mNmeaBuffer.add(new Nmea(timestamp, nmea));
  26. }
  27. Message msg = Message.obtain();
  28. msg.what = NMEA_RECEIVED;
  29. // remove any NMEA_RECEIVED messages already in the queue
  30. mGpsHandler.removeMessages(NMEA_RECEIVED);
  31. mGpsHandler.sendMessage(msg);
  32. }
  33. }
  34. private final Handler mGpsHandler = new Handler() {
  35. @Override
  36. public void handleMessage(Message msg) {
  37. if (msg.what == NMEA_RECEIVED) {
  38. synchronized (mNmeaBuffer) {
  39. int length = mNmeaBuffer.size();
  40. for (int i = 0; i < length; i++) {
  41. Nmea nmea = mNmeaBuffer.get(i);
  42. mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
  43. }
  44. mNmeaBuffer.clear();
  45. }
  46. } else {
  47. // synchronize on mGpsStatus to ensure the data is copied atomically.
  48. }
  49. }
  50. }
  51. };
  52. }

在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 plaincopy print?
  1. frameworks\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 plaincopy print?
  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. private final class Listener implements IBinder.DeathRecipient {
  6. final IGpsStatusListener mListener;
  7. Listener(IGpsStatusListener listener) {
  8. mListener = listener;
  9. }
  10. @Override
  11. public void binderDied() {
  12. if (DEBUG) Log.d(TAG, "GPS status listener died");
  13. synchronized (mListeners) {
  14. mListeners.remove(this);
  15. }
  16. if (mListener != null) {
  17. mListener.asBinder().unlinkToDeath(this, 0);
  18. }
  19. }
  20. }
  21. /**
  22. * called from native code to report NMEA data received
  23. */
  24. private void reportNmea(long timestamp) {
  25. synchronized (mListeners) {
  26. int size = mListeners.size();
  27. if (size > 0) {
  28. // don't bother creating the String if we have no listeners
  29. int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
  30. String nmea = new String(mNmeaBuffer, 0, length);
  31. for (int i = 0; i < size; i++) {
  32. Listener listener = mListeners.get(i);
  33. try {
  34. listener.mListener.onNmeaReceived(timestamp, nmea);
  35. } catch (RemoteException e) {
  36. Log.w(TAG, "RemoteException in reportNmea");
  37. mListeners.remove(listener);
  38. // adjust for size of list changing
  39. size--;
  40. }
  41. }
  42. }
  43. }
  44. }
  45. }

GPS定位功能最终需要调用硬件实现,操作硬件就必须通过C/C++完成,GpsLocationProvider中包含许多native方法,采用JNI机制为上层提供服务。
在上面的Code Frame中,通过调用本地方法native_read_nmea()获取到NMEA数据,然后传数据到IGpsStatusListener接口类的onNmeaReceived()方法。
reportNmea()是被JNI方法回调的方法,在 JNI 的实现中,通过这些方法的回调来传递JNI层的执行结果。

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

native_read_nmea()在GpsLocationProvider类中定义:

[java] view plaincopy print?
  1. private native int native_read_nmea(byte[] buffer, int bufferSize);

native指明它是本地方法,和它对应的C/C++文件的实现是:

[cpp] view plaincopy print?
  1. static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj, jbyteArray nmeaArray, jint buffer_size);

How?Next...

[cpp] view plaincopy print?
  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 plaincopy print?
  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 plaincopy print?
  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 plaincopy print?
  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 plaincopy print?
  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 plaincopy print?
  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 plaincopy print?
  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. // fail if the main interface fails to initialize
  7. if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
  8. return false;
  9. /* other codes */
  10. return true;
  11. }

而android_location_GpsLocationProvider_init()在GpsLocationProvider类中调用native_init()时被调用:

[cpp] view plaincopy print?
  1. static JNINativeMethod sMethods[] = {
  2. /* name, signature, funcPtr */
  3. {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init}
  4. }
[cpp] view plaincopy print?
  1. 这里,我们找到了和上层的关系,和下层如何打交道呢?
  2. 下面需要贴一大段代码:
[cpp] view plaincopy print?
  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 plaincopy print?
  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 plaincopy print?
  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 plaincopy print?
  1. hardware\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 plaincopy print?
  1. hardware\qcom\gps\loc_api\libloc_api\gps.c
  2. extern const GpsInterface* gps_get_hardware_interface();
  3. const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
  4. {
  5. return gps_get_hardware_interface();
  6. }
  7. static int open_gps(const struct hw_module_t* module, char const* name,
  8. struct hw_device_t** device)
  9. {
  10. struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
  11. memset(dev, 0, sizeof(*dev));
  12. dev->common.tag = HARDWARE_DEVICE_TAG;
  13. dev->common.version = 0;
  14. dev->common.module = (struct hw_module_t*)module;
  15. dev->get_gps_interface = gps__get_gps_interface;
  16. *device = (struct hw_device_t*)dev;
  17. return 0;
  18. }
  19. static struct hw_module_methods_t gps_module_methods = {
  20. .open = open_gps
  21. };

流程很清楚了:
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 plaincopy print?
  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. .start = gps_start,
  12. --设置GPS的状态为开始:GPS_STATUS_SESSION_BEGIN
  13. .stop = gps_stop,
  14. --设置GPS的状态为结束:GPS_STATUS_SESSION_END
  15. .cleanup = gps_cleanup,
  16. --退出需要进行的一些清理工作,如GpsState->init = STATE_QUIT,GpsCallbacks指针归null,信号量回收
  17. .inject_time = gps_inject_time,
  18. --可为空函数
  19. .inject_location = gps_inject_location,
  20. --可为空函数
  21. .delete_aiding_data = gps_delete_aiding_data,
  22. --可为空函数
  23. .set_position_mode = gps_set_position_mode,
  24. --设置GPS工作模式:单GPS、单BD、GPS/BD双系统
  25. .get_extension = gps_get_extension,
  26. --定位之外的扩展功能实现
  27. };
  28. state->thread = state->callbacks.create_thread_cb("gps", gps_state_thread, state);
  29. --static void gps_state_thread(void*  arg):
  30. 1、state通过arg参数传入函数
  31. 2、创建了Time和Nmea数据处理两个线程
  32. state->nmea_thread = state->callbacks.create_thread_cb("nmea_thread", gps_nmea_thread, state);
  33. --static void gps_nmea_thread(void*  arg)
  34. --gps_opentty(state);
  35. nmea_reader_init(reader);
  36. --nmea_reader_parse(NmeaReader*  r) {
  37. if (gps_state->callbacks.nmea_cb) {
  38. struct timeval tv;
  39. unsigned long long mytimems;
  40. gettimeofday(&tv,NULL);
  41. mytimems = tv.tv_sec * 1000 + tv.tv_usec / 1000;
  42. gps_state->callbacks.nmea_cb(mytimems, r->in, r->pos);
  43. D("reader_parse. %.*s ", r->pos, r->in );
  44. }
  45. }

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

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

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

【Android架构GPS篇】之定位数据如何从GPS芯片到应用层相关推荐

  1. android 数据业务,【Android架构Telephony篇】之数据业务(一)

    Android: 4.4.4 Desktop: Ubuntu 15.04 这里只做一些准备事情. 不得不说,Android里的Telephony模块还是挺复杂的,要想搞个八九分清楚需要花点功夫.今天把 ...

  2. VC++实现GPS全球定位系统定位数据的提取

    VC++实现GPS全球定位系统定位数据的提取 来源:MCUBLOG   作者:未知 字体大小:[大][中][小] 引言 卫星导航技术的飞速发展已逐渐取代了无线电导航.天文导航等传统导航技术,而成为一种 ...

  3. php gps数据处理,使用c++提取GPS全球定位系统定位数据

    摘 要:本文主要针对GPS导航定位系统,对其卫星定位信息的接收及其定位参数提取的实现方法予以介绍,并使用C++可视化编程技术得以实现. 关键字:c++;GPS全球定位系统定位;GPS数据提取 Abst ...

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

    定位的基础知识: 1.定位芯片和CPU之间通过串口进行通信 2.串口和CPU之间传输的是ASCII格式的NMEA(National Marine Electronics Association)信息, ...

  5. VC++提取GPS全球定位系统定位数据

    引言 卫星导航技术的飞速发展已逐渐取代了无线电导航.天文导航等传统导航技术,而成为一种普遍采用的导航定位技术,并在精度.实时性.全天候等方面取得了长足进步.现不仅应用于物理勘探.电离层测量和航天器导航 ...

  6. Byte学堂:公交GPS及IC卡数据原理及分析方法

    公交数据是指公交在营运过程中产生的交易.车辆运行等数据,通过对公交大数据进行深入的分析和挖掘,可以有效地监控城市道路交通运作状况及公交系统运营状况,及时.合理发现问题,调度交通资源,提高公交运力,缓解 ...

  7. Android架构篇-1 项目组织架构

    Android架构篇-1 项目组织架构 模块化分层 1.结构清晰,各模块代码分离,符合高内聚低耦合,快速定位查找代码 2.团队协作开发灵活,互不影响,各模块完成后合并即可完成整体app 3.抽离公共层 ...

  8. Android 集成高德地图——当前定位,添加图标,画路线,设置显示中心位置,比例,地图刷新位置监听,判断GPS开启,去打开GPS

    /*** 判断定位服务是否开启** @param* @return true 表示开启*/ public static boolean isLocationEnabled(Context contex ...

  9. Android通过NTRIP协议获取差分数据实现高精度定位

    https://www.jianshu.com/p/7b93952febc0 项目背景 最近在做一个Android的APP项目中有个功能,需要用到Ntrip协议从差分服务器获取差分数据,并将差分数据通 ...

最新文章

  1. vue 封装dialog_element-dialog封装成子组件
  2. 八零后高薪程序员感慨中年危机,月薪五万多,想要跳槽没地方!
  3. python函数结构图_Python数据结构与算法之图结构(Graph)实例分析
  4. 网页浏览器知道我们的哪些信息?(1)
  5. gzip和gunzip 解压参数
  6. Rabbit and Grass【博弈】
  7. kafka php 教程,php的kafka踩坑(一)
  8. 【已解决】Failed to start cron.service: Unit cron.service not found.
  9. OpenCV用C画线代码示例
  10. 计算机自动重启快捷键,待机和重启电脑的快捷键
  11. halcon算子翻译——cooc_feature_matrix
  12. Android第三方视频加载框架JCVideoPlayer
  13. 基于javaweb+mysql的高校学生会社团管理系统(前台、后台)
  14. UniswapV2配对合约里的函数选择器与事件选择器
  15. 武汉大学计算机技术上机难度,武汉大学计算机技术(专业学位)考研难不难和研究生专业好不好...
  16. 供应链管理起源:不能不提日本
  17. 知识库管理系统对于企业有哪些作用及优势?
  18. UEditor 富文本编辑器-后端实现文件上传功能
  19. The contents in the strings file of the famous IM app.
  20. 开课吧:C++学习的方向是什么?

热门文章

  1. 内核态文件操作【转】
  2. Windows下AndroidStudio 中使用Git(AndroidStudio项目于GitHub关联)
  3. JAVA操作文件大全(二)
  4. Spring 应用开发框架 Spring Boot 2.3.0 最新版本发布
  5. 滑铁卢大学计算机科学双录取,滑铁卢大学双录取要求
  6. BMP文件格式详解(BMP file format) (转)
  7. FastReport数据库连接路径及软件的最终分发数据库路径问题
  8. ViT (Vision Transformer) ---- RNN
  9. lua mysql 字符串截取_Lua 截取字符串(截取utf-8格式字符串)
  10. onenote快捷键_onenote快捷键的高效用法