作者:朱克锋
转载请注明出处:http://blog.csdn.net/linux_zkf/article/details/7493129
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=数据无效)