前段时间在调试Android的时候,涉及到sensors的移植,在Android中 Sensors子系统架构如下:其中Sensor HAL以上都已由android实现的,在具体Android Sensors移植中,需要用户实现的sensor Hal及以下,下面我们来分析一下sensors HAL的具体实现

Sensors的硬件抽像层中,有几个关键的结构体需要用户处理,它的定义位于libhardware/include/hardware/sensors.h文件中,sensors_module_t结构体用来定义sensor模块,sensor_t结构体用来定义一个sensors设备,sensors_event_t用来定义sensor数据,sensors_poll_device_t用来定义sensor的控制

sensors.c主要实现sensors_module_t和sensor_t结构体,定义了sensors模块的主要功能

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include "SensorsControl.h"

#ifdef LOG_TAG

#undef LOG_TAG

#endif

#define LOG_TAG     "yamaha_sensors"

#define YLOGD(...) LOGD(__VA_ARGS__)

#define YLOGI(...) LOGI(__VA_ARGS__)

#define YLOGE(...) LOGE(__VA_ARGS__)

#define YLOGW(...) LOGW(__VA_ARGS__)

//--------------------------------------------------------------------------------------------------------

#define POLLTIMEOUT         (-1)

#define MAX_DEVICE_NAME     (32)

#define MAX_CLASS_PATH      (256)

//--------------------------------------------------------------------------------------------------------

static const    struct sensor_t sSupportedSensors[NUM_SENSORS] = {

#if defined(SENSOR_SUPPORT_ACCELEROMETER)

{

.name        = "BMA150 3-axis Accelerometer",

.vendor      = "Bosh",

.version     = 120,

.handle      = ID_ACCELEROMETER,

.type        = SENSOR_TYPE_ACCELEROMETER,

.maxRange    = 4.0f * 9.81f,

.resolution  = (4.0f * 9.81f)/256.0f,

.power       = 2.0f,

.reserved    = {0},

},

#endif

#if defined(SENSOR_SUPPORT_MAGNETIC_FIELD)

{

.name        = "MS-3C Magnetic Sensor",

.vendor      = "Yamaha Corporation",

.version     = 120,

.handle      = ID_MAGNETIC_FIELD,

.type        = SENSOR_TYPE_MAGNETIC_FIELD,

.maxRange    = 2000.0f,

.resolution  = 1.0f/16.0f,

.power       = 4.0f,   /* typ 4mA (Normal), typ 1uA (Standby) */

.reserved    = {0},

},

#endif

#if defined(SENSOR_SUPPORT_ORIENTATION)

{

.name        = "MS-3C Orientation Sensor",

.vendor      = "Yamaha Corporation",

.version     = 120,

.handle      = ID_ORIENTATION,

.type        = SENSOR_TYPE_ORIENTATION,

.maxRange    = 360.0f,

.resolution  = 1.0f,

.power       = 1.0f,

.reserved    = {0},

},

#endif

};

//--------------------------------------------------------------------------------------------------------

static int  sensors_list(struct sensors_module_t *module, struct sensor_t const**sensor)

{

*sensor = sSupportedSensors;

return  NUM_SENSORS;

}

//--------------------------------------------------------------------------------------------------------

static int  open_sensors(const struct hw_module_t* module, const char* name,struct hw_device_t** device)

{

YLOGD("open_sensors");

return  init_sensors_control(module, device);

}

//--------------------------------------------------------------------------------------------------------

static struct hw_module_methods_t sensors_module_methods = {

.open = open_sensors,

};

//--------------------------------------------------------------------------------------------------------

const struct sensors_module_t HAL_MODULE_INFO_SYM = {

.common = {

.tag            = HARDWARE_MODULE_TAG,

.version_major  = 1,

.version_minor  = 2,

.id             = SENSORS_HARDWARE_MODULE_ID,

.name           = "Yamaha Sensors module",

.author         = "Yamaha Corporation",

.methods        = &sensors_module_methods,

},

.get_sensors_list   = sensors_list,

};

SensorBace.cpp:为各sensors实现的基类,openDataFd会返回sensors EVENT设备文件的句柄

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

//--------------------------------------------------------------------------------------------------------

#include "SensorBase.h"

//--------------------------------------------------------------------------------------------------------

#ifdef LOG_TAG

#undef LOG_TAG

#endif

#define LOG_TAG     "SensorBase"

#define YLOGD(...) LOGD(__VA_ARGS__)

#define YLOGI(...) LOGI(__VA_ARGS__)

#define YLOGE(...) LOGE(__VA_ARGS__)

#define YLOGW(...) LOGW(__VA_ARGS__)

//--------------------------------------------------------------------------------------------------------

SensorBase::SensorBase(const char* name) : name(name), data_fd(-1),mHasPendingEvent(false), mEnabled(0)

{

data_fd = openDataFd(name);

// sysfs classpath read

if (getInputClasspath(name) < 0)    YLOGE("getInputClasspath failed [%s]\n", name);

YLOGD("SensorBase::SensorBase : [Name : %s, data_fd : %d, classname : %s]\n", name, data_fd, classpath);

}

//--------------------------------------------------------------------------------------------------------

SensorBase::~SensorBase() {

if (data_fd >= 0)   close(data_fd);

}

//--------------------------------------------------------------------------------------------------------

int SensorBase::getFd() const {

return  data_fd;

}

//--------------------------------------------------------------------------------------------------------

int SensorBase::setDelay(int32_t handle, int64_t ns) {

int err = 0;

int msDelay = (int)(ns / 1000000LL);        // convert to ms

YLOGD("SensorBase::setDelay : [Name : %s, Handle : %d, ns : %lld, delay = %d]\n", name, handle, ns, msDelay);

if (setInputAttr("delay", msDelay) < 0) {

YLOGE("setInputAttr failed -> delay : [%s]\n", name);   err = -1;

}

return  err;

}

//--------------------------------------------------------------------------------------------------------

int SensorBase::enable(int32_t handle, int enabled) {

int err = 0;

YLOGD("SensorBase::enable : [Name : %s, Handle : %d, enabled : %d]\n",name, handle, enabled);

// class path -> set enable, set wake

if (setInputAttr("enable", enabled) < 0) {

YLOGE("setInputAttr failed -> enable : [%s]\n", name);  err = -1;

}

if (setInputAttr("wake", enabled) < 0) {

YLOGE("setInputAttr failed -> wake : [%s]\n", name);    err = -1;

}

mEnabled = enabled;    mHasPendingEvent = true;

return  err;

}

//--------------------------------------------------------------------------------------------------------

int SensorBase::getInitialValues(sensors_vec_t* sensor, float divf) {

char    buf[sizeof("-2147483647") * 3 + 1]; /* including spaces, LF and '\0' */

char    *p, space[] = " ";

int     i;

if (getInputAttr("data", buf, sizeof(buf)) < 0) {

for (= 0; i < 3; i++)     sensor->v[i] = 0;

return 0;

}

for (= 0; i < 3; i++) {

if (== 0)     p = strtok(buf, space);

else            p = strtok(NULL, space);

if (== NULL)  sensor->v[i] = 0;

else            sensor->v[i] = atoi(p) / divf;

YLOGD("initial value[%s] [%.3f]\n", name, sensor->v[i]);

}

return 0;

}

//--------------------------------------------------------------------------------------------------------

int SensorBase::getInitialStatus(sensors_vec_t* sensor) {

int status;

if (getInputAttr("status", &status) < 0)    sensor->status = 0;

else                                        sensor->status =(int8_t)status;

YLOGD("SensorBase::getInitialStatus : [Name : %s, status : %d]\n", name,status);

return 0;

}

//--------------------------------------------------------------------------------------------------------

bool SensorBase::hasPendingEvents() const {

return  mHasPendingEvent;

}

//--------------------------------------------------------------------------------------------------------

int64_t SensorBase::getTimestamp() {

struct timespec t;

t.tv_sec = t.tv_nsec = 0;

clock_gettime(CLOCK_MONOTONIC, &t);

return int64_t(t.tv_sec)*1000000000LL + t.tv_nsec;

}

//--------------------------------------------------------------------------------------------------------

int SensorBase::getInputClasspath(const char *inputName)    {

DIR             *dir;

const char      *dirname = "/sys/class/input";

char            buf[PATH_MAX];

struct dirent   *de;

int             fd = -1, nread, found = 0;

if (name == NULL || classpath == NULL)  return -EINVAL;

// Open Input class dir

if((dir = opendir(dirname)) == NULL)    return  -errno;

while((de = readdir(dir))) {

if (strncmp(de->d_name, "input", strlen("input")) != 0) continue;

memset(classpath, 0x00, sizeof(classpath));

snprintf(classpath, PATH_MAX, "%s/%s/", dirname, de->d_name);

snprintf(buf, sizeof(buf), "%s/name", classpath);

if((fd = open(buf, O_RDONLY)) < 0)  continue;

if ((nread = read(fd, buf, sizeof(buf))) < 0) {

close(fd);

continue;

}

buf[nread - 1] = '\0';

if (strcmp(buf, inputName) == 0) {

close(fd);    closedir(dir);    return 0;   // Classpath found!!

}

close(fd);  fd = -1;

}

closedir(dir);  *classpath = '\0';

return -EINVAL;     // Classpath not found

}

//--------------------------------------------------------------------------------------------------------

int SensorBase::getInputAttr(const char *attr, char *value, int len)    {

char    fname[PATH_MAX];

int     fd, nread;

if (classpath == NULL || *classpath == '\0' || attr == NULL || value ==NULL || len < 1)    return -EINVAL;

memset(fname, 0x00, sizeof(fname));

snprintf(fname, sizeof(fname), "%s/%s", classpath, attr);   fname[sizeof(fname) - 1] = '\0';

if((fd = open(fname, O_RDONLY)) < 0)    return -errno;

if ((nread = read(fd, value, len)) < 0) {

close(fd);  return -errno;

}

close(fd);

value[nread - 1] = '\0';

return 0;

}

//--------------------------------------------------------------------------------------------------------

int SensorBase::getInputAttr(const char *attr, int *value)  {

char buf[sizeof("-2147483647")];

int rt;

if (value == NULL)  return -EINVAL;

if ((rt = getInputAttr(attr, buf, sizeof(buf))) < 0)    return rt;

*value = atoi(buf);

return 0;

}

//--------------------------------------------------------------------------------------------------------

int SensorBase::setInputAttr(const char *attr, char *value, int len)    {

char fname[PATH_MAX];

int fd;

if (classpath == NULL || *classpath == '\0' || attr == NULL || value ==NULL || len < 1)    return -EINVAL;

memset(fname, 0x00, sizeof(fname));

snprintf(fname, sizeof(fname), "%s/%s", classpath, attr);  fname[sizeof(fname) - 1] = '\0';

if((fd = open(fname, O_WRONLY)) < 0)    return  -errno;

if (write(fd, value, len) < 0) {

close(fd);  return -errno;

}

close(fd);

return 0;

}

int SensorBase::setInputAttr(const char *attr, int value)   {

char buf[sizeof("-2147483647")];

memset(buf, 0x00, sizeof(buf));

sprintf(buf, "%d", value);

return setInputAttr(attr, buf, sizeof(buf));

}

int SensorBase::openDataFd(const char *inputName)   {

DIR             *dir;

struct dirent   *de;

const char      *dirname = "/dev/input";

char            *filename, devname[PATH_MAX];

int             fd = -1;

if((dir = opendir(dirname)) == NULL)    return -1;

memset(devname, 0x00, sizeof(devname)); strcpy(devname, dirname);

filename = devname + strlen(devname);   *filename++ = '/';

while((de = readdir(dir))) {

if(de->d_name[0] == '.' && (de->d_name[1] == '\0' || (de->d_name[1] =='.' && de->d_name[2] == '\0')))

continue;

strcpy(filename, de->d_name);

if((fd = open(devname, O_RDONLY)) >= 0) {

char name[80];

if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1)     name[0]= '\0';

if (!strcmp(name, inputName))                               break;

else {

close(fd);  fd = -1;

}

}

}

closedir(dir);

LOGE_IF(fd < 0, "couldn't find '%s' input device", inputName);

return  fd;

}

InputEventReader.cpp文件的主要功能会读取sensors的输入事件

#include

#include

#include

#include

#include

#include

#include

#include

#include "InputEventReader.h"

/*****************************************************************************/

struct input_event;

InputEventCircularReader::InputEventCircularReader(size_t numEvents)

: mBuffer(new input_event[numEvents * 2]),

mBufferEnd(mBuffer + numEvents),

mHead(mBuffer),

mCurr(mBuffer),

mFreeSpace(numEvents)

{

}

InputEventCircularReader::~InputEventCircularReader()

{

delete [] mBuffer;

}

ssize_t InputEventCircularReader::fill(int fd)

{

size_t numEventsRead = 0;

if (mFreeSpace) {

const ssize_t nread = read(fd, mHead, mFreeSpace * sizeof(input_event));

if (nread<0 || nread % sizeof(input_event)) {

// we got a partial event!!

return nread<0 ? -errno : -EINVAL;

}

numEventsRead = nread / sizeof(input_event);

if (numEventsRead) {

mHead += numEventsRead;

mFreeSpace -= numEventsRead;

if (mHead > mBufferEnd) {

size_t s = mHead - mBufferEnd;

memcpy(mBuffer, mBufferEnd, s * sizeof(input_event));

mHead = mBuffer + s;

}

}

}

return numEventsRead;

}

ssize_t InputEventCircularReader::readEvent(input_event const** events)

{

*events = mCurr;

ssize_t available = (mBufferEnd - mBuffer) - mFreeSpace;

return available ? 1 : 0;

}

void InputEventCircularReader::next()

{

mCurr++;

mFreeSpace++;

if (mCurr >= mBufferEnd) {

mCurr = mBuffer;

}

}

SensorsControl.cpp文件为sensors的控制文件,实现sensors_poll_device_t结构体,在init_sensors_control函数中写义了sensors_poll_context_t类的对像,在sensors_poll_context_t类的构造函数中, 定义了具体sensors类的对像,init_sensors_control函数是在sensors模块被打开时调用的

//-------------------------------------------------------------------

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

//-------------------------------------------------------------------

#include "SensorsControl.h"

#include "AccelerometerSensor.h"

#include "GeomagneticSensor.h"

#include "OrientationSensor.h"

//-------------------------------------------------------------------

#ifdef LOG_TAG

#undef LOG_TAG

#endif

#define LOG_TAG     "SensorsControl"

#define YLOGD(...)

//#define YLOGD(...) LOGD(__VA_ARGS__)

#define YLOGI(...) LOGI(__VA_ARGS__)

#define YLOGE(...) LOGE(__VA_ARGS__)

#define YLOGW(...) LOGW(__VA_ARGS__)

//-------------------------------------------------------------------

struct sensors_poll_context_t {

struct sensors_poll_device_t device; // must be first

sensors_poll_context_t  ();

~sensors_poll_context_t ();

int activate    (int handle, int enabled);

int setDelay    (int handle, int64_t ns);

int pollEvents  (sensors_event_t* data, int count);

private:

enum {

Accelerometer   = 0,

Geomagnetic     = 1,

Orientation     = 2,

numSensorDrivers,

numFds,

};

static const size_t     wake            = numFds - 1;

static const char       WAKE_MESSAGE    = 'W';

struct pollfd           mPollFds[numFds];

int                     mWritePipeFd;

SensorBase*             mSensors[numSensorDrivers];

int handleToDriver(int handle) const {

if(handle < numSensorDrivers)   return  handle;

return  -EINVAL;

}

};

//-------------------------------------------------------------------

sensors_poll_context_t::sensors_poll_context_t()

{

mSensors[Accelerometer]         = new AccelerometerSensor();

mPollFds[Accelerometer].fd      = mSensors[Accelerometer]->getFd();

mPollFds[Accelerometer].events  = POLLIN;

mPollFds[Accelerometer].revents = 0;

mSensors[Geomagnetic]           = new GeomagneticSensor();

mPollFds[Geomagnetic].fd        = mSensors[Geomagnetic]->getFd();

mPollFds[Geomagnetic].events    = POLLIN;

mPollFds[Geomagnetic].revents   = 0;

mSensors[Orientation]           = new OrientationSensor();

mPollFds[Orientation].fd        = mSensors[Orientation]->getFd();

mPollFds[Orientation].events    = POLLIN;

mPollFds[Orientation].revents   = 0;

int wakeFds[2];

int result = pipe(wakeFds);

LOGE_IF(result<0, "error creating wake pipe (%s)", strerror(errno));

fcntl(wakeFds[0], F_SETFL, O_NONBLOCK);

fcntl(wakeFds[1], F_SETFL, O_NONBLOCK);

mWritePipeFd = wakeFds[1];

mPollFds[wake].fd       = wakeFds[0];

mPollFds[wake].events   = POLLIN;

mPollFds[wake].revents  = 0;

}

//--------------------------------------------------------------------------------------------------------

sensors_poll_context_t::~sensors_poll_context_t() {

for (int i=; i<numSensorDrivers ; i++) {

delete mSensors[i];

}

close(mPollFds[wake].fd);

close(mWritePipeFd);

}

//--------------------------------------------------------------------------------------------------------

int sensors_poll_context_t::activate(int handle, int enabled) {

YLOGD("sensors_poll_context_t::activate : [Handle : %d, enabled : %d]\n",handle, enabled);

int index = handleToDriver(handle);

if (index < 0) return index;

int err =  mSensors[index]->enable(handle, enabled);

if (enabled && !err) {

const char wakeMessage(WAKE_MESSAGE);

int result = write(mWritePipeFd, &wakeMessage, 1);

LOGE_IF(result<0, "error sending wake message (%s)", strerror(errno));

}

return err;

}

//-------------------------------------------------------------------

int sensors_poll_context_t::setDelay(int handle, int64_t ns) {

int index = handleToDriver(handle);

if (index < 0) return index;

return mSensors[index]->setDelay(handle, ns);

}

//-------------------------------------------------------------------

int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count)

{

int nbEvents = 0;

int n = 0;

YLOGD("IN ----> sensors_poll_context_t::pollEvents : [count : %d]\n",count);

do {

// see if we have some leftover from the last poll()

for (int i=; count && i<numSensorDrivers ; i++) {

SensorBase* const sensor(mSensors[i]);

if ((mPollFds[i].revents & POLLIN) || (sensor->hasPendingEvents())){

int nb = sensor->readEvents(data, count);

if (nb < count) {

// no more data for this sensor

mPollFds[i].revents = 0;

}

count -= nb;

nbEvents += nb;

data += nb;

}

}

if (count) {

YLOGD("sensors_poll_context_t :: %d\n", count);

// we still have some room, so try to see if we can get

// some events immediately or just wait if we don't have

// anything to return

= poll(mPollFds, numFds, nbEvents ? 0 : -1);

if (n<0) {

LOGE("poll() failed (%s)", strerror(errno));

return -errno;

}

if (mPollFds[wake].revents & POLLIN) {

char msg;

int result = read(mPollFds[wake].fd, &msg, 1);

LOGE_IF(result<0, "error reading from wake pipe (%s)",strerror(errno));

LOGE_IF(msg != WAKE_MESSAGE, "unknown message on wake queue (0x%02x)", int(msg));

mPollFds[wake].revents = 0;

}

}

// if we have events and space, go read them

} while (&& count);

YLOGD("OUT ----> sensors_poll_context_t::pollEvents : [count : %d, nbEvents]\n", count, nbEvents);

return nbEvents;

}

//-------------------------------------------------------------------

static int poll__close(struct hw_device_t *dev)

{

sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;

if (ctx) {

delete ctx;

}

return 0;

}

//-------------------------------------------------------------------

static int poll__activate(struct sensors_poll_device_t *dev,

int handle, int enabled) {

sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;

return ctx->activate(handle, enabled);

}

//-------------------------------------------------------------------

static int poll__setDelay(struct sensors_poll_device_t *dev,

int handle, int64_t ns) {

sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;

return ctx->setDelay(handle, ns);

}

//-------------------------------------------------------------------

static int poll__poll(struct sensors_poll_device_t *dev,

sensors_event_t* data, int count) {

sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;

return ctx->pollEvents(data, count);

}

//-------------------------------------------------------------------

int init_sensors_control(hw_module_t const* module, hw_device_t** device)

{

int status = -EINVAL;

sensors_poll_context_t *dev = new sensors_poll_context_t();

memset(&dev->device, 0, sizeof(sensors_poll_device_t));

dev->device.common.tag      = HARDWARE_DEVICE_TAG;

dev->device.common.version  = 0;

dev->device.common.module   = const_cast<hw_module_t*>(module);

dev->device.common.close    = poll__close;

dev->device.activate        = poll__activate;

dev->device.setDelay        = poll__setDelay;

dev->device.poll            = poll__poll;

*device = &dev->device.common;

status = 0;

return status;

}

AccelerometerSensor.cpp文件为具体重力加速度传感器的实现

//-------------------------------------------------------------------#include

#include

#include

#include

#include

#include

#include

#include

//-------------------------------------------------------------------

#include "AccelerometerSensor.h"

//-------------------------------------------------------------------

#ifdef LOG_TAG

#undef LOG_TAG

#endif

#define LOG_TAG     "AccelerometerSensor"

#define YLOGD(...) LOGD(__VA_ARGS__)

#define YLOGI(...) LOGI(__VA_ARGS__)

#define YLOGE(...) LOGE(__VA_ARGS__)

#define YLOGW(...) LOGW(__VA_ARGS__)

//-------------------------------------------------------------------

AccelerometerSensor::AccelerometerSensor() :

SensorBase(INPUT_CLASSNAME_ACCELEROMETER), mfdiv(1000000), mInputReader(4)

{

memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));

mPendingEvent.version   = sizeof(sensors_event_t);

mPendingEvent.sensor    = ID_ACCELEROMETER;

mPendingEvent.type      = SENSOR_TYPE_ACCELEROMETER;

// Initialize AccelerometerSensor

getInitialStatus(&mPendingEvent.acceleration);

getInitialValues(&mPendingEvent.acceleration, mfdiv);

}

//-------------------------------------------------------------------

AccelerometerSensor::~AccelerometerSensor() {

}

//-------------------------------------------------------------------intAccelerometerSensor::readEvents(sensors_event_t* data, int count)

{

if (count < 1)  return -EINVAL;

if (mHasPendingEvent) {

mHasPendingEvent        = false;

mPendingEvent.timestamp = getTimestamp();

*data = mPendingEvent;

return  mEnabled ? 1 : 0;

}

ssize_t n = mInputReader.fill(data_fd);

if (< 0)      return n;

int numEventReceived = 0, breaked = 0;

input_event const* event;

while (count && mInputReader.readEvent(&event)) {

switch(event->type) {

case    EV_ABS:

switch(event->code) {

case    ABS_X:      mPendingEvent.acceleration.= event->value / mfdiv;    break;

case    ABS_Y:      mPendingEvent.acceleration.= event->value / mfdiv;    break;

case    ABS_Z:      mPendingEvent.acceleration.= event->value / mfdiv;    break;

case    ABS_STATUS: mPendingEvent.acceleration.status =event->value;       break;

case    ABS_WAKE:   breaked =1;                                            break;

default :

break;

}

break;

case    EV_SYN:

mPendingEvent.timestamp = timevalToNano(event->time);

if (mEnabled) {

*data++ = mPendingEvent;

count--;

numEventReceived++;

}

break;

default :

YLOGE("unknown event (type=%d, code=%d)", event->type, event->code);

break;

}

mInputReader.next();

}

if(breaked)     {

YLOGE("ABS_WAKE event (type=%d, code=%d) : break!!", event->type,event->code);

return  0;

}

return numEventReceived;

}

android sensors相关推荐

  1. Android Sensors (2) 传感器API的使用

    识别传感器和传感器能力 Android sensor framework提供了一些方法,使得你在运行时可以方便地查看设备上都有哪些传感器. API也提供了一些让你获取每个传感器性能的方法. 首先,你需 ...

  2. android 移植 距离感应,Android sensors移植文档

    1  硬件工作原理 1.1 G-sensor主要管脚定义 上图是LIS3DHTR在TD_100中的原理图 l 电压:VDD:sensor的供电电源. VDD_IO:sensor的IO电源. l 中断: ...

  3. Android Sensors (3) 传感器坐标系统

    传感器坐标系统 通常,sensor framework使用一个标准的三轴坐标系统来表达数值. 对于大多数传感器来说,坐标系统是相对于设备屏幕来说的. 当一个设备被放在其默认的方向上时,X轴是水平指向右 ...

  4. Android: android sensors, HAL范例

    从源码找到的一个例子,写的很优雅,不知道HAL怎么写的同学可以好好学习一下: view plaincopy to clipboardprint? /* * Copyright (C) 2008 The ...

  5. android sensors 总结(一)

    Agenda: 1 sensor 介绍 2 sensor架构 3 sensor driver 4 sensor hal 5 sensor校准 1 sensor 介绍 Sensors是将环境中物理指标经 ...

  6. 关于Android 传感器坐标与读数的进一步讨论

    关于Android 传感器坐标与读数的进一步讨论 之前一些相关的讨论见: Android Sensors (3) 传感器坐标系统 Android Sensors (5) 运动传感器 Motion Se ...

  7. android传感器_Android传感器

    android传感器 In this tutorial, we'll be digging deep into the world of Android Sensors. Our smartphone ...

  8. Android Sendor框架介绍

    1    Sensors介绍 1.1      Android Sensors 简介 每一部搭载Android智能操作系统的设备都具有一系列传感器,用于测量运动,方向,和各种环境条件.如果你想要监测装 ...

  9. Android自动接听和挂断电话实现原理

    转自:http://bbs.51cto.com/thread-1078059-1.html 一  前言 这两天要研究类似白名单黑名单以及手势自动接听的一些功能,所以呢,自然而然的涉及到怎么自动接听/挂 ...

最新文章

  1. Python staticmethod() 函数
  2. 信息检索顶会SIGIR 2021大奖出炉!山东大学荣获最佳学生论文
  3. 5G将如何推动未来十年智能城市的发展
  4. [转载]读塔莎奶奶的美好生活
  5. Python爬虫(十)_XPath与lxml类库
  6. (转载)浏览器兼容性问题大汇总
  7. mysql集群经常无法truncate_失败的mysql cluster配置-无法顺利转换已有数据
  8. C++ using的三种使用策略以及具体的用法
  9. entity framework不查数据库修改或排除指定字段集合通用方法
  10. PowerDesigner建立与数据库的连接,以便生成数据库和从数据库生成到PD中
  11. 数据库创建联合主键(MySql)
  12. 域控制器诊断工具 (dcdiag.exe)
  13. Docker学习总结(31)——使用Maven插件构建docker镜像
  14. Mysql支持中文全文检索的插件mysqlcft-应用中的问题
  15. linux下client命令,Linux系统smbclient命令的使用方法
  16. 2022年3月份报告合集(共353份)
  17. 汽车软件行业工程师详细介绍?(上)
  18. 关于H.265/HEVC视频压缩标准相较H.264/AVC节省50%左右的带宽方案的推荐
  19. JavaScript不清不楚之Array.isArray
  20. MySQL索引创建、删除及事务控制

热门文章

  1. Linux属于单用户单任务,()是一种单用户,单任务的微机操作系统。AUNIXBDOSCWinDowsDLinux...
  2. Python基础学习(1)
  3. vs下载问题:请检查网络连接
  4. c#动态生成控件,并为控件注册事件
  5. 公交/地铁出行的场景,需要考虑哪些测试点
  6. 汤唯遭“封杀”被证实 广电总局:对事不对人
  7. Android的Button属性使用
  8. Python:pandas groupby实现类似excel中averageifs函数的功能
  9. DIV怎么自动添加滚动条?并给滚动条添加样式
  10. ‘latin-1‘ codec can‘t encode characters in position 103-115: Body (‘一串中文‘) is not valid Latin-1