【Android架构GPS篇】之定位数据怎样从GPS芯片到应用层
Android:V4.2.2 Source Insight
寫在前面
在漫長的Android源代碼編譯等待過程中,想起之前寫過一部分的Android定位實(shí)現(xiàn)的探究小品,于是繼續(xù)探究。
注:代碼都是片段化的代碼,用來提綱挈領(lǐng)的說明問題。
定位的基礎(chǔ)知識:
1、定位芯片和CPU之間通過串口進(jìn)行通信
2、串口和CPU之間傳輸?shù)氖茿SCII格式的NMEA(National Marine Electronics Association)信息,如:
$GPGGA,092204.999,4250.5589,S,14718.5084,E,1,04,24.4,19.7,M,,,,0000*1F $GPGLL,4250.5589,S,14718.5084,E,092204.999,A*2D $GPGSV,3,1,10,20,78,331,45,01,59,235,47,22,41,069,,13,32,252,45*70 $GPRMC,092204.999,A,4250.5589,S,14718.5084,E,0.00,89.68,211200,,*25
基于以上兩點(diǎn),要探知定位數(shù)據(jù)從GPS芯片到應(yīng)用層的流程,最好的途徑就是從應(yīng)用層輸出NEMA信息的地方開始。
NMEA資料參見:衛(wèi)星定位數(shù)據(jù)NMEA介紹
一、GPS定位的應(yīng)用層實(shí)現(xiàn)
Luckily,在應(yīng)用層我們能夠通過onNmeaReceived()方法獲取到NMEA信息。例如以下Code Fragment:
public class GpsTestActivity extends ActionBarActivity {
/* Other Codes */
/** 獲取系統(tǒng)的定位服務(wù),記得在AndroidManifest中賦予定位方面的權(quán)限:
* <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
* <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
* <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
*/
LocationManager mLocationService = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mLocationService.addNmeaListener(mNmeaListener);
private GpsStatus.NmeaListener mNmeaListener = new NmeaListener() {
@Override
public void onNmeaReceived(long timestamp, String nmea) {
System.out.println(nmea + "
");
}
};
}
二、GPS定位的Framework層實(shí)現(xiàn)
GpsStatus.NmeaListener是一個(gè)接口類。來自GpsStatus.java文件:
frameworksaselocationjavaandroidlocationGpsStatus.java
/**
* Used for receiving NMEA sentences from the GPS.
* NMEA 0183 is a standard for communicating with marine electronic devices
* and is a common method for receiving data from a GPS, typically over a serial port.
* See <a >NMEA 0183</a> for more details.
* You can implement this interface and call {@link LocationManager#addNmeaListener}
* to receive NMEA data from the GPS engine.
*/
public interface NmeaListener {
void onNmeaReceived(long timestamp, String nmea);
}
在上述App中。我們的應(yīng)用程序?qū)崿F(xiàn)了該方法。一旦NMEA數(shù)據(jù)到來。onNmeaReceived()方法就被調(diào)用一次,我們在Console上能夠看到原始的NEMA信息。
那么接下來,就要尋找nmea數(shù)據(jù)的來源了。
mNmeaListener通過LocationManager類的addNmeaListener()方法進(jìn)行注冊(register):
frameworksaselocationjavaandroidlocationLocationManager.java
/**
* Adds an NMEA listener.
*
* @param listener a {@link GpsStatus.NmeaListener} object to register
*
* @return true if the listener was successfully added
*
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
*/
public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
boolean result;
/* mNmeaListeners是LocationManager類的成員變量:
* private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
* new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>();
*/
if (mNmeaListeners.get(listener) != null) {
// listener is already registered
return true;
}
try {
GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
result = mService.addGpsStatusListener(transport);
if (result) {
mNmeaListeners.put(listener, transport);
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
result = false;
}
return result;
}
這里,先檢測定義的NmeaListener有沒有被注冊過。若果沒有。注冊之。
注冊到哪里去了呢?
由mNmeaListeners成員的定義可知。和GpsStatus.NmeaListener進(jìn)行關(guān)聯(lián)的是GpsStatusListenerTransport。而它是LocationManager類的一個(gè)內(nèi)部類。
僅僅看相關(guān)的部分:
// This class is used to send GPS status events to the client's main thread.
private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {
private final GpsStatus.NmeaListener mNmeaListener;
// This must not equal any of the GpsStatus event IDs
private static final int NMEA_RECEIVED = 1000;
private class Nmea {
long mTimestamp;
String mNmea;
Nmea(long timestamp, String nmea) {
mTimestamp = timestamp;
mNmea = nmea;
}
}
private ArrayList<Nmea> mNmeaBuffer;
//G psStatusListenerTransport(GpsStatus.Listener listener){}
GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
mNmeaListener = listener;
mListener = null;
mNmeaBuffer = new ArrayList<Nmea>();
}
@Override
public void onNmeaReceived(long timestamp, String nmea) {
if (mNmeaListener != null) {
synchronized (mNmeaBuffer) {
mNmeaBuffer.add(new Nmea(timestamp, nmea));
}
Message msg = Message.obtain();
msg.what = NMEA_RECEIVED;
// remove any NMEA_RECEIVED messages already in the queue
mGpsHandler.removeMessages(NMEA_RECEIVED);
mGpsHandler.sendMessage(msg);
}
}
private final Handler mGpsHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == NMEA_RECEIVED) {
synchronized (mNmeaBuffer) {
int length = mNmeaBuffer.size();
for (int i = 0; i < length; i++) {
Nmea nmea = mNmeaBuffer.get(i);
mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
}
mNmeaBuffer.clear();
}
} else {
// synchronize on mGpsStatus to ensure the data is copied atomically.
}
}
}
};
}
在GpsStatusListenerTransport類中:
定義一個(gè)Nmea類型的鏈表mNmeaBuffer。一旦onNmeaReceived()接收到NMEA數(shù)據(jù),新數(shù)據(jù)被載入到鏈表mNmeaBuffer中(mNmeaBuffer.add(new Nmea(timestamp, nmea))),然手置消息標(biāo)志為NMEA_RECEIVED(msg.what = NMEA_RECEIVED)。
mGpsHandler對上述NMEA_RECEIVED消息進(jìn)行處理。終于把傳過來的NMEA數(shù)據(jù)發(fā)往應(yīng)用層GpsTestActivity中的onNmeaReceived()。
那么。GpsStatusListenerTransport類中onNmeaReceived(long timestamp, String nmea)方法的nmea數(shù)據(jù)有誰提供呢?
GpsStatusListenerTransport類繼承自IGpsStatusListener,由類前的字符"I"我們得知,它是一個(gè)擴(kuò)展名為.aidl的文件。
注:
AIDL:AIDL機(jī)制用來完畢在進(jìn)程之間進(jìn)行通信(在Android中不同意進(jìn)程間共享數(shù)據(jù)),它的具體知識另外Google之。
這里,我們再次見到了onNmeaReceived():
rameworksaselocationjavaandroidlocationIGpsStatusListener.aidl
oneway interface IGpsStatusListener
{
void onGpsStarted();
void onGpsStopped();
void onFirstFix(int ttff);
void onSvStatusChanged(int svCount, in int[] prns, in float[] snrs, in float[] elevations, in float[] azimuths, int ephemerisMask, int almanacMask, int usedInFixMask);
void onNmeaReceived(long timestamp, String nmea);
}
注:
onewaykeyword是用來修飾遠(yuǎn)程調(diào)用行為。使用該關(guān)鍵詞時(shí)。遠(yuǎn)程調(diào)用不是堵塞的,它僅僅是發(fā)送事物數(shù)據(jù)并馬上返回。
接口的終于實(shí)現(xiàn)是把普通的遠(yuǎn)程調(diào)用依照Binder線程池的調(diào)用規(guī)則來接收,假設(shè)oneway是使用在本地調(diào)用上,那么不會有不論什么影響,而且調(diào)用依舊是異步的。
以下。探究必須進(jìn)入第三層。
三、GPS定位的Lib層實(shí)現(xiàn)
和IGpsStatusListener接頭的是GpsLocationProvider類:
frameworksaseservicesjavacomandroidserverlocationGpsLocationProvider.java
public class GpsLocationProvider implements LocationProviderInterface {
// 此處省略1000+N行
private ArrayList<Listener> mListeners = new ArrayList<Listener>();
private final class Listener implements IBinder.DeathRecipient {
final IGpsStatusListener mListener;
Listener(IGpsStatusListener listener) {
mListener = listener;
}
@Override
public void binderDied() {
if (DEBUG) Log.d(TAG, "GPS status listener died");
synchronized (mListeners) {
mListeners.remove(this);
}
if (mListener != null) {
mListener.asBinder().unlinkToDeath(this, 0);
}
}
}
/**
* called from native code to report NMEA data received
*/
private void reportNmea(long timestamp) {
synchronized (mListeners) {
int size = mListeners.size();
if (size > 0) {
// don't bother creating the String if we have no listeners
int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
String nmea = new String(mNmeaBuffer, 0, length);
for (int i = 0; i < size; i++) {
Listener listener = mListeners.get(i);
try {
listener.mListener.onNmeaReceived(timestamp, nmea);
} catch (RemoteException e) {
Log.w(TAG, "RemoteException in reportNmea");
mListeners.remove(listener);
// adjust for size of list changing
size--;
}
}
}
}
}
}
GPS定位功能終于須要調(diào)用硬件實(shí)現(xiàn),操作硬件就必須通過C/C++完畢。GpsLocationProvider中包括很多native方法,採用JNI機(jī)制為上層提供服務(wù)。
在上面的Code Frame中,通過調(diào)用本地方法native_read_nmea()獲取到NMEA數(shù)據(jù),然后傳數(shù)據(jù)到IGpsStatusListener接口類的onNmeaReceived()方法。
reportNmea()是被JNI方法回調(diào)的方法,在 JNI 的實(shí)現(xiàn)中。通過這些方法的回調(diào)來傳遞JNI層的運(yùn)行結(jié)果。
源代碼編譯出錯(cuò),解決這個(gè)問題去。。。
native_read_nmea()在GpsLocationProvider類中定義:
private native int native_read_nmea(byte[] buffer, int bufferSize);
native指明它是本地方法。和它相應(yīng)的C/C++文件的實(shí)現(xiàn)是:
static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj, jbyteArray nmeaArray, jint buffer_size);
How?Next...
frameworksaseservicesjnicom_android_server_location_GpsLocationProvider.cpp
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
/* other members... */
{"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
/* other members... */
};
JNINativeMethod是Android中採用的Java和C/C++函數(shù)的映射方式,并在當(dāng)中描寫敘述了函數(shù)的參數(shù)和返回值:
typedef struct {
const char* name; // Java文件里的本地方法
const char* signature; // 述了函數(shù)的參數(shù)和返回值
void* fnPtr; // 指針,指向具體的C/C++函數(shù)
} JNINativeMethod;
具體內(nèi)容這里還是不展開了。
來看android_location_GpsLocationProvider_read_nmea()的實(shí)現(xiàn):
static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj,
jbyteArray nmeaArray, jint buffer_size)
{
// this should only be called from within a call to reportNmea
jbyte* nmea = (jbyte *)env->GetPrimitiveArrayCritical(nmeaArray, 0);
int length = sNmeaStringLength;
if (length > buffer_size)
length = buffer_size;
memcpy(nmea, sNmeaString, length);
env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
return length;
}
盡管不清楚JNI深入含義,但這個(gè)函數(shù)意思還是挺明顯的。我們判斷:
第5行:用來動態(tài)分配內(nèi)存。nmea指向獲取到的內(nèi)存區(qū)域,同一時(shí)候把nmea和nmeaArray進(jìn)行關(guān)聯(lián);
第6行:sNmeaStringLength指示一次從串口讀取到的字節(jié)長度
第7、8行:在Java中調(diào)用native_read_nmea()方法時(shí)指明了我們須要取的數(shù)據(jù)長度,所以,假設(shè)從串口實(shí)際讀取的數(shù)據(jù)長度大于我們須要的,我們對串口數(shù)據(jù)進(jìn)行截取:即。僅僅取指定長度的數(shù)據(jù);
第9行:從串口讀出的數(shù)據(jù)存在sNmeaString中。這里Copy到nmea指向的內(nèi)存區(qū)域;
第10行:nmea指向的內(nèi)存區(qū)域中的數(shù)據(jù)交給nmeaArray,然后釋放nmea指向的內(nèi)存空間。
這里也能夠看到,函數(shù)調(diào)用是通過nmeaArray傳遞NMEA數(shù)據(jù)的
以下應(yīng)該看sNmeaStringLength、sNmeaString的設(shè)置過程:
static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
{
JNIEnv* env = AndroidRuntime::getJNIEnv();
// The Java code will call back to read these values
// We do this to avoid creating unnecessary String objects
sNmeaString = nmea;
sNmeaStringLength = length;
env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
method_reportNmea、、、有沒有熟悉的感覺?
對。在GpsLocationProvider類中見過reportNmea(long timestamp)函數(shù)。
以下的代碼片段表明,method_reportNmea()和reportNmea()是綁定在一起的。調(diào)用C/C++函數(shù)method_reportNmea,也就間接調(diào)用Java的reportNmea()方法。這中間的機(jī)制,就是JNI。
static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
/* other definitions... */
method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
/* other definitions... */
}
而method_reportNmea是在nmea_callback()函數(shù)中被調(diào)用的。哪里又調(diào)用nmea_callback()函數(shù)呢?
Let's go to neXt Layer...
四、GPS定位HAL層的實(shí)現(xiàn)
所謂Android的HAL層。也就是是Linux的應(yīng)用程序。至于串口詳細(xì)配置,比方寄存器配置、數(shù)據(jù)收發(fā)等芯片級實(shí)現(xiàn),是在在Linux內(nèi)核里的。
com_android_server_location_GpsLocationProvider.cpp文件里另外出現(xiàn)nmea_callback的地方是:
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,
request_utc_time_callback,
};
GpsCallbacks結(jié)構(gòu)體封裝了全部須要回調(diào)的函數(shù)(確切的說是函數(shù)指針),sGpsCallbacks調(diào)用關(guān)系:
static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
{
// this must be set before calling into the HAL library
if (!mCallbacksObj)
mCallbacksObj = env->NewGlobalRef(obj);
// fail if the main interface fails to initialize
if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
return false;
/* other codes */
return true;
}
而android_location_GpsLocationProvider_init()在GpsLocationProvider類中調(diào)用native_init()時(shí)被調(diào)用:
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"native_init", "()Z", (void*)android_location_GpsLocationProvider_init}
}
這里,我們找到了和上層的關(guān)系。和下層怎樣打交道呢? 以下須要貼一大段代碼:
/** Represents the standard GPS interface. */
typedef struct {
/** set to sizeof(GpsInterface) */
size_t size;
/**
* Opens the interface and provides the callback routines
* to the implemenation of this interface.
*/
int (*init)( GpsCallbacks* callbacks );
/** Starts navigating. */
int (*start)( void );
/** Stops navigating. */
int (*stop)( void );
/** Closes the interface. */
void (*cleanup)( void );
/** Injects the current time. */
int (*inject_time)(GpsUtcTime time, int64_t timeReference,
int uncertainty);
/** Injects current location from another location provider
* (typically cell ID).
* latitude and longitude are measured in degrees
* expected accuracy is measured in meters
*/
int (*inject_location)(double latitude, double longitude, float accuracy);
/**
* Specifies that the next call to start will not use the
* information defined in the flags. GPS_DELETE_ALL is passed for
* a cold start.
*/
void (*delete_aiding_data)(GpsAidingData flags);
/**
* min_interval represents the time between fixes in milliseconds.
* preferred_accuracy represents the requested fix accuracy in meters.
* preferred_time represents the requested time to first fix in milliseconds.
*/
int (*set_position_mode)(GpsPositionMode mode, GpsPositionRecurrence recurrence,
uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time);
/** Get a pointer to extension information. */
const void* (*get_extension)(const char* name);
} GpsInterface;
GpsInterface結(jié)構(gòu)體封裝了GPS實(shí)現(xiàn)的標(biāo)準(zhǔn)接口——接口,注意!
接口不就時(shí)用來連接兩端的嗎?一端是com_android_server_location_GpsLocationProvider.cpp文件中的實(shí)現(xiàn),那還有一端就是。。。都探到這個(gè)地步了。還有一端應(yīng)該是串口方式直接和GPS芯片打交道的Linux驅(qū)動了吧?
確是。可是還須要一個(gè)媒介:
struct gps_device_t {
struct hw_device_t common;
/**
* Set the provided lights to the provided values.
*
* Returns: 0 on succes, error code on failure.
*/
const GpsInterface* (*get_gps_interface)(struct gps_device_t* dev);
};
然后,
static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
int err;
hw_module_t* module;
/* other codes..*/
err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
hw_device_t* device;
err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
if (err == 0) {
gps_device_t* gps_device = (gps_device_t *)device;
sGpsInterface = gps_device->get_gps_interface(gps_device);
}
}
/* other codes..*/
}
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
}
GpsLocationProvider.java通過class_init_native的調(diào)用實(shí)現(xiàn)對C/C++文件里android_location_GpsLocationProvider_class_init_native的調(diào)用。
com_android_server_location_GpsLocationProvider.cpp通過gps_device_t獲取操作GPS芯片的接口。
How????
重點(diǎn)來了:GPS_HARDWARE_MODULE_ID
對。就是GPS_HARDWARE_MODULE_ID!
往下看:
ardwareqcomgpsloc_apilibloc_apigps.c
struct hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = GPS_HARDWARE_MODULE_ID,
.name = "loc_api GPS Module",
.author = "Qualcomm USA, Inc.",
.methods = &gps_module_methods,
};
有木有?GPS_HARDWARE_MODULE_ID。
hardwareqcomgpsloc_apilibloc_apigps.c
extern const GpsInterface* gps_get_hardware_interface();
const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
{
return gps_get_hardware_interface();
}
static int open_gps(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->get_gps_interface = gps__get_gps_interface;
*device = (struct hw_device_t*)dev;
return 0;
}
static struct hw_module_methods_t gps_module_methods = {
.open = open_gps
};
流程非常清楚了:
gps_get_hardware_interface()函數(shù)在驅(qū)動程序中實(shí)現(xiàn)
——在gps__get_gps_interface()中被調(diào)用
——在open_gps()被調(diào)用
——在gps_module_methods中例化
——HAL_MODULE_INFO_SYM
const GpsInterface* gps_get_hardware_interface()函數(shù)在其它C文件實(shí)現(xiàn)。該C文件是和Linux驅(qū)動打交道的應(yīng)用程序。基本功能:
1、open處理器CPU和GPS芯片連接的串口。
2、read串口NEMA數(shù)據(jù)。并解析。
3、依據(jù)上層傳進(jìn)來的回調(diào)函數(shù)。打包數(shù)據(jù),調(diào)用對應(yīng)Callback。進(jìn)而發(fā)送到Android應(yīng)用層。
static const GpsInterface mGpsInterface = {
.size =sizeof(GpsInterface),
.init = gps_init,
|--1、接收從上層傳下來的GpsCallbacks變量,用它初始化GpsState->callbacks成員
|--2、GpsState結(jié)構(gòu)體的其它成員初始化
|--3、GpsState->init狀態(tài)設(shè)置為:STATE_INIT
|--4、最重要:啟動GPS線程,進(jìn)行數(shù)據(jù)的讀取、處理:
state->thread = state->callbacks.create_thread_cb("gps", gps_state_thread, state);
--gps_create_thread create_thread_cb;
--typedef pthread_t (* gps_create_thread)(const char* name, void (*start)(void *), void* arg);
.start = gps_start,
--設(shè)置GPS的狀態(tài)為開始:GPS_STATUS_SESSION_BEGIN
.stop = gps_stop,
--設(shè)置GPS的狀態(tài)為結(jié)束:GPS_STATUS_SESSION_END
.cleanup = gps_cleanup,
--退出須要進(jìn)行的一些清理工作,如GpsState->init = STATE_QUIT,GpsCallbacks指針歸null。信號量回收
.inject_time = gps_inject_time,
--可為空函數(shù)
.inject_location = gps_inject_location,
--可為空函數(shù)
.delete_aiding_data = gps_delete_aiding_data,
--可為空函數(shù)
.set_position_mode = gps_set_position_mode,
--設(shè)置GPS工作模式:單GPS、單BD、GPS/BD雙系統(tǒng)
.get_extension = gps_get_extension,
--定位之外的擴(kuò)展功能實(shí)現(xiàn)
};
state->thread = state->callbacks.create_thread_cb("gps", gps_state_thread, state);
--static void gps_state_thread(void* arg):
1、state通過arg參數(shù)傳入函數(shù)
2、創(chuàng)建了Time和Nmea數(shù)據(jù)處理兩個(gè)線程
state->nmea_thread = state->callbacks.create_thread_cb("nmea_thread", gps_nmea_thread, state);
--static void gps_nmea_thread(void* arg)
--gps_opentty(state);
nmea_reader_init(reader);
--nmea_reader_parse(NmeaReader* r) {
if (gps_state->callbacks.nmea_cb) {
struct timeval tv;
unsigned long long mytimems;
gettimeofday(&tv,NULL);
mytimems = tv.tv_sec * 1000 + tv.tv_usec / 1000;
gps_state->callbacks.nmea_cb(mytimems, r->in, r->pos);
D("reader_parse. %.*s ", r->pos, r->in );
}
}
我們是從APP層NMEA信息輸出自定向下分析的,APP層信息輸出的終于起始是:gps_state->callbacks.nmea_cb(mytimems, r->in, r->pos);
到這里還有個(gè)問題:GPS芯片和CPU連接,使用的是哪個(gè)串口?這個(gè)串口號怎么確定的呢?
打算貼個(gè)完整HAL層的實(shí)例,考慮到代碼非常多,下篇在說吧。
。。
總結(jié)
以上是生活随笔為你收集整理的【Android架构GPS篇】之定位数据怎样从GPS芯片到应用层的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 项目总结71:Caffeine的基本概念
- 下一篇: 学习OpenCV——绘制彩色直方图(HS