您的位置:首页 > 移动开发 > Android开发

Android系统硬件抽象层原理与实现之GPS

2012-04-24 12:25 776 查看
作者:朱克锋
转载请注明出处:/article/7841107.html

Android系统硬件抽象层原理与实现之GPS
本文我将系统分析一下GPS HAL的实现,GPS大家都很熟悉,原理就不再介绍了。
GPS在android系统中的结构如图

GOS APP
ANDROID LOCATION
GPS JNI
GPS HAL
GPS DRIVER
接下来我们来看看GPS HAL的实现
GPS硬件设备驱动程序通常是串口驱动程序,将GPS连接上应用处理器的某个串口后,就可以打开该节点进行写操作,对GPS写入数据或命令,而读操作一般获取到的就是标准的NMEA数据,NMEA数据下面会有简单介绍。

在android系统中,GPS
HAL代码在
hardware/libhardware_legacy/wifi/gps
hardware/libhardware_legacy/include/libhardware_legacy/gps.h

在gps.h中定义了各种信息,其主要部分如下:
GPS 的标准结构体,里面定义的关于操作GPS的方法指针

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;

这些是GPS的回调函数,是GPS的硬件抽象层获取信息的主要手段,通常在读取到底层数据并分析完成后调用上报信息给上层。

/** 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);

/** Callback for reporting NMEA sentences.
* Can only be called from a thread created by create_thread_cb.
*/
typedef void (* gps_nmea_callback)(GpsUtcTime timestamp, const char* nmea, int length);

/** Callback to inform framework of the GPS engine's capabilities.
* Capability parameter is a bit field of GPS_CAPABILITY_* flags.
*/
typedef void (* gps_set_capabilities)(uint32_t capabilities);

/** Callback utility for acquiring the GPS wakelock.
* This can be used to prevent the CPU from suspending while handling GPS events.
*/
typedef void (* gps_acquire_wakelock)();

/** Callback utility for releasing the GPS wakelock. */
typedef void (* gps_release_wakelock)();

/** Callback for creating a thread that can call into the Java framework code.
* This must be used to create any threads that report events up to the framework.
*/
typedef pthread_t (* gps_create_thread)(const char* name, void (*start)(void *), void* arg);

GpsCallbacks通过调用初始化方法(GpsInterface 的init方法)注册到HAL,共HAL调用

/** 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;

GpsLocation中是解析后的详细信息,可以直接提供给android框架使用,其中解析后包括:经度、纬度、速度、方向、精确度、时间戳等等

/** Represents a location. */
typedef struct {
/** set to sizeof(GpsLocation) */
size_t
size;
/** Contains GpsLocationFlags bits. */
uint16_t
flags;
/** Represents latitude in degrees. */
double
latitude;
/** Represents longitude in degrees. */
double
longitude;
/** Represents altitude in meters above the WGS 84 reference
* ellipsoid. */
double
altitude;
/** Represents speed in meters per second. */
float
speed;
/** Represents heading in degrees. */
float
bearing;
/** Represents expected accuracy in meters. */
float
accuracy;
/** Timestamp for the location fix. */
GpsUtcTime
timestamp;
} GpsLocation;

在gps.c中定义了获取GPS接口的方法,通过一些宏定义来选择

const GpsInterface*
gps_get_interface()


{


if (sGpsInterface == NULL)


gps_find_hardware();


return sGpsInterface;


}


static void
gps_find_hardware( void )


{


#ifdef HAVE_QEMU_GPS_HARDWARE


if (qemu_check()) {


sGpsInterface = gps_get_qemu_interface();


if (sGpsInterface) {


LOGD("using QEMU GPS Hardware emulation\n");


return;


}


}


#endif


#ifdef HAVE_GPS_HARDWARE


sGpsInterface = gps_get_hardware_interface();


#endif


if (!sGpsInterface)


LOGD("no GPS hardware on this device\n");


}


在模拟器中如下所示

const GpsInterface* gps_get_qemu_interface()


{


return &qemuGpsInterface;


}

static const GpsInterface
qemuGpsInterface = {


qemu_gps_init,


qemu_gps_start,


qemu_gps_stop,


qemu_gps_cleanup,


qemu_gps_inject_time,


qemu_gps_inject_location,


qemu_gps_delete_aiding_data,


qemu_gps_set_position_mode,


qemu_gps_get_extension,


};

对于GPS来说首先需要初始化,然后对GPS数据建立一套“获取—解析—上报”的机制,初始化完成以后一般都会开启一个poll线程,对GPS端口进行轮询,获取NMEA数据,获取导数据后进行解析,目的是将数据转换位框架层可以识别的结构信息,在参考代码中有很多种实现,基本上就是文本解析,然后填充上报数据结构

最后简单解释一下NMEA数据结构
NMEA是"National
Marine Electronics Association"(国际海洋电子协会)缩写,同时也是数据传输标准工业协会,在这里,实际上应为NMEA 0183。它是一套定义接收机输出的标准信息,有几种不同的格式,每种都是独立相关的ASCII格式,逗点隔开数据流,数据流长度从30-100字符不等,通常以每秒间隔选择输出,最常用的格式为"GGA",它包含了定位时间,纬度,经度,高度,定位所用的卫星数,DOP值,差分状态和校正时段等,其他的有速度,跟踪,日期等。NMEA实际上已成为所有的GPS接收机和最通用的数据输出格式,同时它也被用于与GPS接收机接口的大多数的软件包里
说明:NMEA0183格式以“$”开始,常用语句有GPGGA,GPVTG,GPRMC等
这里一GPRMC为例简单分析一下
$GPRMC,121252.000,A,3958.3032,N,11629.6046,E,15.15,359.95,070306,,,A*54
<1> UTC时间,hhmmss(时分秒)格式
<2> 定位状态,A=有效定位,V=无效定位
<3> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)
<4> 纬度半球N(北半球)或S(南半球)
<5> 经度dddmm.mmmm(度分)格式(前面的0也将被传输)
<6> 经度半球E(东经)或W(西经)
<7> 地面速率(000.0~999.9节,前面的0也将被传输)
<8> 地面航向(000.0~359.9度,以真北为参考基准,前面的0也将被传输)
<9> UTC日期,ddmmyy(日月年)格式
<10> 磁偏角(000.0~180.0度,前面的0也将被传输)
<11> 磁偏角方向,E(东)或W(西)
<12> 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: