Android2.3.4ジャイロ移植


一背景
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サービス側を接続します.
振り返ってみましょう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
y=%f
z=%f
",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(); } }