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ファイルの下のセンサ配列定義.
ジャイロセンサーのみで他のセンサー定義を削除
3.sensorsを修正する.cppのsensors_poll_context_t構造体、他のセンサ定義を削除
コンストラクション関数を含む:
3.GyroSensorを修正する.cppのgetFd()関数は,元の戻りgyroデバイスが駆動するファイル記述子をsocketを返すファイル記述子に変更する.
ここでmSocketFdはGyroSensor.hで新しく定義されたsocketファイル記述子、socket_connect()関数はsocketサービス側を接続します.
振り返ってみましょうcppファイルのsensors_poll_context_tコンストラクション関数:
ここでgyroクラスを初期化してgetFd()でsocketファイル記述子を取得し、poll関数でファイル記述子を読み出し、pollの読み出しはsensors_poll_context_t::pollEvents関数では、コードを変更する必要はありません.
4.gyroクラスのコンストラクション関数を変更し、デバイス駆動に関連するコードを削除します.
5.gyroクラスの他のメンバー関数を修正し、setDelay、enable、setInitialStateなどの関数のコードをすべて削除します.
6.gyroクラスのreadEvents関数を変更します.この関数は最も重要な関数で、socketからgyroデータを読み込むには:
sokcetサービス側は、毎回2バイトのデータを送信し、単軸ジャイロであるため、1つのデータしかなく、mPendingEventのdataデータを3バイトとも同じデータに埋め込み、*dataに値を付け、最後に1を返し、1つのデータを読み上げることを表す.
7.libsensorsの下のAndroidを修正する.mkファイル:
8.コンパイル後、sensorsを生成する.default.soファイルはlib/hwディレクトリに、hwディレクトリの下にあるsensors文字のsoファイルを削除し、sensorsだけを残す.default.soファイルは、シミュレータまたはデバイス上でテストできます.AppレイヤのJavaテストプログラムは次のとおりです.
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();
}
}