现在的位置: 首页 > 综合 > 正文

Android2.3.4陀螺仪移植

2013年08月05日 ⁄ 综合 ⁄ 共 8787字 ⁄ 字号 评论关闭

一 背景

1.需求

   陀螺仪硬件并非接在android cpu上,所以不存在陀螺仪驱动,而陀螺仪数据是通过用户空间的一个c程序传过来。

2.思路

   修改陀螺仪hal层,在hal层构建socket客户端,在数据源的c程序上构建socket服务端。一旦有数据,c程序通过socket发送数据到陀螺仪hal层,并上报。


二 步骤

1.把device/samsung/crespo/libsensors目录拷贝到hardware/libhardware/modules目录下

2.修改sensors.cpp文件下的传感器数组定义。

因只用到陀螺仪传感器,把其他传感器定义删掉

static const struct sensor_t sSensorList[] = {
/*
        { "KR3DM 3-axis Accelerometer",
          "STMicroelectronics",
          1, SENSORS_ACCELERATION_HANDLE,
          SENSOR_TYPE_ACCELEROMETER, RANGE_A, CONVERT_A, 0.23f, 20000, { } },
        { "AK8973 3-axis Magnetic field sensor",
          "Asahi Kasei Microdevices",
          1, SENSORS_MAGNETIC_FIELD_HANDLE,
          SENSOR_TYPE_MAGNETIC_FIELD, 2000.0f, CONVERT_M, 6.8f, 16667, { } },
        { "AK8973 Orientation sensor",
          "Asahi Kasei Microdevices",
          1, SENSORS_ORIENTATION_HANDLE,
          SENSOR_TYPE_ORIENTATION, 360.0f, CONVERT_O, 7.8f, 16667, { } },
        { "GP2A Light sensor",
          "Sharp",
          1, SENSORS_LIGHT_HANDLE,
          SENSOR_TYPE_LIGHT, 3000.0f, 1.0f, 0.75f, 0, { } },
        { "GP2A Proximity sensor",
          "Sharp",
          1, SENSORS_PROXIMITY_HANDLE,
          SENSOR_TYPE_PROXIMITY, 5.0f, 5.0f, 0.75f, 0, { } },
*/
        { "K3G Gyroscope sensor",
          "STMicroelectronics",
          1, SENSORS_GYROSCOPE_HANDLE,
          SENSOR_TYPE_GYROSCOPE, RANGE_GYRO, CONVERT_GYRO, 6.1f, 1190, { } },
};


3.修改sensors.cpp的sensors_poll_context_t结构体,删除其他的传感器定义

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 {
        //light           = 0,
        //proximity       = 1,
        //akm             = 2,
        //gyro            = 3,
        gyro		= 0,
        numSensorDrivers,
        numFds,
    };

    static const size_t wake = numFds - 1; //wake = 1
    static const char WAKE_MESSAGE = 'W';
    struct pollfd mPollFds[numFds];//2
    int mWritePipeFd;
    SensorBase* mSensors[numSensorDrivers];// 2

    int handleToDriver(int handle) const {
        switch (handle) {
			/*
            case ID_A:
            case ID_M:
            case ID_O:
                return akm;
            case ID_P:
                return proximity;
            case ID_L:
                return light;
			*/
            case ID_GY:
                return gyro;
        }
        return -EINVAL;
    }
};

包括构造函数:

sensors_poll_context_t::sensors_poll_context_t()
{
/*
    mSensors[light] = new LightSensor();
    mPollFds[light].fd = mSensors[light]->getFd();
    mPollFds[light].events = POLLIN;
    mPollFds[light].revents = 0;

    mSensors[proximity] = new ProximitySensor();
    mPollFds[proximity].fd = mSensors[proximity]->getFd();
    mPollFds[proximity].events = POLLIN;
    mPollFds[proximity].revents = 0;

    mSensors[akm] = new AkmSensor();
    mPollFds[akm].fd = mSensors[akm]->getFd();
    mPollFds[akm].events = POLLIN;
    mPollFds[akm].revents = 0;

*/
	//LOGD("sensors_poll_context_t");
    mSensors[gyro] = new GyroSensor();
    mPollFds[gyro].fd = mSensors[gyro]->getFd();
    mPollFds[gyro].events = POLLIN;
    mPollFds[gyro].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];

	//wake equals 1
    mPollFds[wake].fd = wakeFds[0];//store the reading fd of the pipe
    mPollFds[wake].events = POLLIN;
    mPollFds[wake].revents = 0;
}



3.修改GyroSensor.cpp的getFd()函数,把原来的返回gyro设备驱动的文件描述符,改为返回socket的文件描述符。

 int GyroSensor::getFd()
{
	if(mSocketFd == -1){
		socket_connect();
	}

	return mSocketFd;
}


其中,mSocketFd是在GyroSensor.h中新定义的socket文件描述符,socket_connect()函数实现连接socket服务端。

我们回过头看sensors.cpp文件的sensors_poll_context_t构造函数:

mSensors[gyro] = new GyroSensor();
    mPollFds[gyro].fd = mSensors[gyro]->getFd();
    mPollFds[gyro].events = POLLIN;
    mPollFds[gyro].revents = 0;


这里初始化gyro类后,通过getFd()获取socket文件描述符,然后就可以通过poll函数对文件描述符进行读取数据,poll的读取在sensors_poll_context_t::pollEvents函数中,代码都不用改变,像这样:


int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count)
{
	//what does parameter count mean ? fuck 
    int nbEvents = 0;
    int n = 0;
	//LOGD("sensors_poll_context_t::pollEvents");
	//LOGD("count=%d",count);

    do {
        // see if we have some leftover from the last poll()
        for (int i=0 ; 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) {
            // 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
            n = poll(mPollFds, numFds, nbEvents ? 0 : -1);
            if (n<0) {
                LOGE("poll() failed (%s)", strerror(errno));
                return -errno;
            }
			//read data from pipe
            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 (n && count);

	

    return nbEvents;
}


4.修改gyro类的构造函数,把与设备驱动相关的那一段代码删除:


GyroSensor::GyroSensor()
    : SensorBase(NULL, "gyro"),
      mEnabled(0),
      mInputReader(4),
      mHasPendingEvent(false),
      mEnabledTime(0),
      mSocketFd(-1)
{
	//LOGD("GyroSensor::GyroSensor");
    mPendingEvent.version = sizeof(sensors_event_t);
    mPendingEvent.sensor = ID_GY;
    mPendingEvent.type = SENSOR_TYPE_GYROSCOPE;
    memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));


	/*
    if (data_fd) {
        strcpy(input_sysfs_path, "/sys/class/input/");
        strcat(input_sysfs_path, input_name);
        strcat(input_sysfs_path, "/device/");
        input_sysfs_path_len = strlen(input_sysfs_path);
        enable(0, 1);
    }

	*/
}

5.修改gyro类的其他成员函数,包括setDelay,enable,setInitialState等函数里面的代码去全部删除:

int GyroSensor::setInitialState() {

	/*
    struct input_absinfo absinfo_x;
    struct input_absinfo absinfo_y;
    struct input_absinfo absinfo_z;
    float value;
    if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_GYRO_X), &absinfo_x) &&
        !ioctl(data_fd, EVIOCGABS(EVENT_TYPE_GYRO_X), &absinfo_y) &&
        !ioctl(data_fd, EVIOCGABS(EVENT_TYPE_GYRO_X), &absinfo_z)) {
        value = absinfo_x.value;
        mPendingEvent.data[0] = value * CONVERT_GYRO_X;
        value = absinfo_x.value;
        mPendingEvent.data[1] = value * CONVERT_GYRO_Y;
        value = absinfo_x.value;
        mPendingEvent.data[2] = value * CONVERT_GYRO_Z;
        mHasPendingEvent = true;
    }

	
	*/

	//LOGD("GyroSensor::setInitialState");
    return 0;
}




int GyroSensor::enable(int32_t, int en) {
	/*
    int flags = en ? 1 : 0;
    if (flags != mEnabled) {
        int fd;
        strcpy(&input_sysfs_path[input_sysfs_path_len], "enable");
        fd = open(input_sysfs_path, O_RDWR);
        if (fd >= 0) {
            char buf[2];
            int err;
            buf[1] = 0;
            if (flags) {
                buf[0] = '1';
                mEnabledTime = getTimestamp() + IGNORE_EVENT_TIME;
            } else {
                buf[0] = '0';
            }
            err = write(fd, buf, sizeof(buf));
            close(fd);
            mEnabled = flags;
            setInitialState();
            return 0;
        }
        return -1;
    }
	*/

	//LOGD("GyroSensor::enable");
    return 0;
}

int GyroSensor::setDelay(int32_t handle, int64_t delay_ns)
{
/*
    int fd;
    strcpy(&input_sysfs_path[input_sysfs_path_len], "poll_delay");
    fd = open(input_sysfs_path, O_RDWR);
    if (fd >= 0) {
        char buf[80];
        sprintf(buf, "%lld", delay_ns);
        write(fd, buf, strlen(buf)+1);
        close(fd);
        return 0;
    }
	return -1;
*/
	//LOGD("GyroSensor::setDelay");
	return 0;
    
}

6.修改gyro类的readEvents函数,这个函数是最重要的函数,要从socket中读取gyro数据:

float value = 0;
	char buf[2];
	int nread = 0;

	nread = read(mSocketFd, buf, 2);
	if(nread <= 0){
		LOGE("GyroSensor::readEvents read error.");
		return 0;
	}
	
	float value = (float)((buf[0] << 8) + buf[1]);
	//LOGD("gyro_msg_handle, value=%f",value);
	value *= CONVERT_GYRO_X;

	
	mPendingEvent.data[0] = value;
	mPendingEvent.data[1] = value;
	mPendingEvent.data[2] = value;

	*data = *mPendingEvent;

	return 1;

sokcet服务端每次发送2个字节数据,因是单轴陀螺仪,所以只有1个数据,把mPendingEvent的data数据3个字节都填充同一数据,然后赋值给*data,最后返回1,表述读到1个数据。


7.修改libsensors下的Android.mk文件的:


LOCAL_MODULE := sensors.default


8.编译后,生成sensors.default.so文件到lib/hw目录,把hw目录下其他有sensors文字的so文件删除,只留sensors.default.so文件,然后就可以在模拟器或设备上进行测试了,App层的Java测试程序如下:

package com.hase.ng102.sensors;

import android.R.string;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class SensorDemoActivity extends Activity {
	//设置LOG标签
    private static final String TAG = "sensors";
	private  SensorManager sm;
	private TextView tv1;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        tv1 = (TextView)this.findViewById(R.id.tv1); 
        sm = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
        Log.d(String.format("getSystemService %s", sm == null ? "sucess":"fail"), TAG);
        int sensorType = Sensor.TYPE_GYROSCOPE;
        sm.registerListener(myAccelerometerListener,sm.getDefaultSensor(sensorType),SensorManager.SENSOR_DELAY_NORMAL);
    }
    
    /*
     * SensorEventListener接口的实现,需要实现两个方法
     * 方法1 onSensorChanged 当数据变化的时候被触发调用
     * 方法2 onAccuracyChanged 当获得数据的精度发生变化的时候被调用,比如突然无法获得数据时
     * */
    final SensorEventListener myAccelerometerListener = new SensorEventListener(){
        
        //复写onSensorChanged方法//
        public void onSensorChanged(SensorEvent sensorEvent){
            if(sensorEvent.sensor.getType() == Sensor.TYPE_GYROSCOPE){
                Log.i(TAG,"onSensorChanged");
                
                //图解中已经解释三个值的含义
                float x = sensorEvent.values[0];
                float y = sensorEvent.values[1];
                float z = sensorEvent.values[2];
                
                String msg = String.format("x=%f\n y=%f\n z=%f\n",x,y,z);
                tv1.setText(msg);
                Log.i(TAG, msg);
            }
            else {
            	String msg = "other sensors data changed";
            	tv1.setText(msg);
				Log.i(TAG, msg);
			}
        }
        //复写onAccuracyChanged方法
        public void onAccuracyChanged(Sensor sensor , int accuracy){
            Log.i(TAG, "onAccuracyChanged");
        }
    };
    
    public void onPause(){
        /*
         * 很关键的部分:注意,说明文档中提到,即使activity不可见的时候,感应器依然会继续的工作,测试的时候可以发现,没有正常的刷新频率
         * 也会非常高,所以一定要在onPause方法中关闭触发器,否则讲耗费用户大量电量,很不负责。
         * */
        sm.unregisterListener(myAccelerometerListener);
        super.onPause();
    }
    
    
    
}




抱歉!评论已关闭.