一 背景
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; }
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(); } }