導航:首頁 > 操作系統 > android驅動例子

android驅動例子

發布時間:2023-05-31 14:43:00

Ⅰ 如何在android的驅動程序中對加速度感測器的數據進行方向和坐標的轉

一部智能手機或便攜設備應具有Wi-Fi 和互聯網功能,能夠運行應用軟體等諸多特徵,而且一定會具有內置感測器。高端智能手機可能集成接近感測器,環境光感測器,3
軸加速度計,以及磁力計等多種感測器。 Android 2.3
添加了一些支持多種新型感測器的API,包括陀螺儀、旋轉向量、線性加速度、重力和氣壓感測器等。應用軟體可以使用這些新型感測器,將它們組合起來,就可以實現高精確度的高級運動檢測功能。

3 軸加速度計或低g 值感測器是Android API
支持的感測器之一,具有特定的坐標系統,可以給應用程序提供標準的介面數據。坐標空間的定義與手機屏幕的默認方向有關,如圖1所示。



1. 3 軸加速度計的Android 坐標系統

在Android 坐標系統中,坐標原點位於屏幕的左下角,X 軸水平指向右側,Y 軸垂直指向頂部,Z
軸指向屏幕前方。在該系統中,屏幕後方的坐標具有負的Z 軸值。Android 加速度計數據定義為:

Sensor.TYPE_ACCELEROMETER

所有數值都採用SI
標准單位(m/s2),測量手機的加速度值,並減去重力加速度分量。

values[0]:x 軸上的加速度值減去Gx
values[1]:y
軸上的加速度值減去Gy
values[2]:z 軸上的加速度值減去Gz

例如,當設備平放在桌上並推著其左側向右移動時,x
軸加速度值為正。當設備平放在桌上時,加速度值為+9.81,這是用設備的加速度值 (0 m/s2) 減去重力加速度值 (-9.81 m/s2)得到的。


當設備平放在桌上放,並以加速度A m/s2 朝天空的方向推動時,加速度值等於A+9.81,這是用設備加速度值(+A
m/s2)減去重力加速度值(-9.81 m/s2)得到的。

表 1
列出了與設備的各個位置相對應的感測器的加速度值讀數。用戶可以用下表檢查加速度計的方向與系統坐標是否一致。

在 Android HAL 文件中改變 X、Y 和Z 軸的方向

在 HAL
文件中,會有一組宏定義,用於把從感測器中讀取的加速度數據轉換為標准單位(m/s2)。如以下代碼:

// conversion of
acceleration data to SI units (m/s^2)
#define CONVERT_A (GRAVITY_EARTH /
LSG)
#define CONVERT_A_X (-CONVERT_A)
#define CONVERT_A_Y (CONVERT_A)

#define CONVERT_A_Z (CONVERT_A)

在這個宏定義中,常量GRAVITY_EARTH
是一個標准重力加速度值,即9.81m/s2,LSG為一個重力加速度值的最小有效計數值,例如,MMA8452
在正常模式下的讀數為1024。因此,CONVERT_A 用於把從加速度感測器中讀取的數據,從數字讀數轉換為標准重力加速度單位。


通過分別修改CONVERT_A_X、CONVERT_A_Y 和CONVERT_A_Z,我們可以輕松地改變X、Y 和Z
軸的方向。如果該軸的方向與系統定義相反,可以使用(-CONVERT_A)來改變其方向。如果方向一致,就使用(CONVERT_A),則保持方向不變。


這個宏定義位於FSL Android 9 (Android 2.2)驅動程序的HAL文件sensor.c 中。對於FSLAndroid 10
(Android 2.3),您可以在』libsensors』文件夾的HAL 文件Sensor.h 中找到它。

在 Android 2.2 HAL
文件中交換X 軸和Y 軸

在某些情況下,X 和Y 軸必須進行交換,以便使感測器數據的坐標與系統坐標保持一致。

對於 FSL
Android 9 (Android 2.2)驅動程序來說,X 軸和Y 軸的交換非常簡單。首先,在HAL 文件sensor.c
中,在函數sensor_poll() 中找到以下代碼:

switch (event.code) {
case ABS_X:

sSensors.acceleration.x = event.value * CONVERT_A_X;
break;
case
ABS_Y:
sSensors.acceleration.y = event.value * CONVERT_A_Y;
break;

case ABS_Z:
sSensors.acceleration.z = event.value * CONVERT_A_Z;

break;
}

然後,根據如下所示修改代碼:

switch (event.code) {
case
ABS_X:
sSensors.acceleration.y = event.value * CONVERT_A_Y;
break;

case ABS_Y:
sSensors.acceleration.x = event.value * CONVERT_A_X;

break;
case ABS_Z:
sSensors.acceleration.z = event.value *
CONVERT_A_Z;
break;
}

在 Android 2.3 的HAL 文件中交換X 軸和Y 軸


Android 2.3 的HAL 文件中交換X 軸和Y 軸會更加復雜些,因為它具有更復雜的HAL文件結構。所有HAL
文件都位於文件夾『libsensors』中。文件AccelSensor.cpp 中的兩個函數需要修改。


首先,修改函數AccelSensor()的代碼,如下所示:

if
(accel_is_sensor_enabled(SENSOR_TYPE_ACCELEROMETER)) {
mEnabled |=
1<<accelerometer; if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_X),
&absinfo)) {
mPendingEvents[Accelerometer].acceleration.y =
absinfo.value * CONVERT_A_Y;
}
if (!ioctl(data_fd,
EVIOCGABS(EVENT_TYPE_ACCEL_Y), &absinfo)) {

mPendingEvents[Accelerometer].acceleration.x = absinfo.value * CONVERT_A_X;

}
if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Z), &absinfo)) {

mPendingEvents[Accelerometer].acceleration.z = absinfo.value * CONVERT_A_Z;

}
}

然後,修改函數processEvent()的代碼,如下所示:

void
AccelSensor::processEvent(int code, int value)
{
switch (code) {

case EVENT_TYPE_ACCEL_X:
mPendingMask |= 1<<accelerometer; mPendingEvents[Accelerometer].acceleration.y = value * CONVERT_A_Y;
break;

case EVENT_TYPE_ACCEL_Y:
mPendingMask |= 1<<accelerometer; mPendingEvents[Accelerometer].acceleration.x = value * CONVERT_A_X;
break;

case EVENT_TYPE_ACCEL_Z:
mPendingMask |= 1<<accelerometer; mPendingEvents[Accelerometer].acceleration.z = value * CONVERT_A_Z;
break;

}
}

完成後,X 軸和Y 軸的數據就互相交換了。

在 Kernel 驅動文件中交換X 軸和Y 軸


X 軸和Y 軸的數據交換可以在底層的linux 驅動中,在剛開始讀取感測器數據時實施。通過這種方法,無論感測器晶元以何種方式安裝在PCB
中,或者使用各種不同類型的感測器,HAL 文件都可以保持一致。

對於 Android 2.2 和2.3
來說,執行該操作的最便捷的方式是修改函數report_abs()中的代碼。在該函數中,感測器數據通過調用函數mma8452_read_data()讀取,如下所示(當使用的感測器為MMA8452Q
時):

if (mma8452_read_data(&x,&y,&z) != 0) {

//DBG("mma8452 data read failed ");
return; }

X 軸和Y
軸可以通過以下方式輕松交換:

if (mma8452_read_data(&y,&x,&z) != 0) {

//DBG("mma8452 data read failed ");
return; }

對於 Android
2.2,MMA8452 的Kernel 驅動文件為mma8452.c;對於Android 2.3,驅動文件是『hwmon』文件夾中的mxc_mma8452.c。


在 Kernel 驅動文件中改變 X、Y 和Z 軸的方向

感測器數據的方向也可以在Kernel
驅動文件中更改。以下帶有注釋的語句可以添加到函數report_abs()中,從而改變數據方向:

if
(mma8452_read_data(&y,&x,&z) != 0) {
//DBG("mma8452 data read
failed ");
return;
}
x *= -1; //Reverse X direction
y *= -1;
//Reverse Y direction
z *= -1; //Reverse Z direction

input_report_abs(mma8452_idev->input, ABS_X, x);

input_report_abs(mma8452_idev->input, ABS_Y, y);

input_report_abs(mma8452_idev->input, ABS_Z, z);

input_sync(mma8452_idev->input);

總結

Android
系統已經為加速度計定義了坐標系統,因此用戶必須轉換從實際感測器中讀取的數據,從而與其保持一致。無論是否需要轉換,都應檢查X、Y 和Z
軸的方向以及X-Y軸坐標。我們可以更改HAL 文件或Kernel 驅動文件來改變軸的方向,或交換X 和Y 軸,但是不要同時修改HAL 文件和Kernel 驅動。

找找

Ⅱ 誰有沒有Android串口的使用例子

1 首先做的是創建新的工程然後添加一下文件


3代碼

好了 然後就是關於這個頁面的Code了,

這是我的:

package android.serialport;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.BreakIterator;
import java.util.ServiceConfigurationError;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MyserialActivity extendsActivity
{
EditText sendedit;
EditText receiveedit;
FileInputStream mInStream;
FileOutputStream mOutStream;
SerialPort classserialport;
ReadThread mReadThread;

private class ReadThread extends Thread
{
public void run()
{
super.run();
while(!isInterrupted())
{
int size;
}
}
}


void onDataReceive(final byte[] buffer,finalint size)
{
runOnUiThread(new Runnable()
{

@Override
publicvoid run()
{
// TODO Auto-generated method stub
if(mReadThread != null)
{
receiveedit.append(newString(buffer,0,size));
}
}
});
}
@Override
protectedvoid onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_myserial);

sendedit= (EditText)findViewById(R.id.editText1);
receiveedit=(EditText)findViewById(R.id.editText2);


receiveedit.setFocusable(false);//進制輸入
/*
* 打開串口
* */
finalButton openserial =(Button)findViewById(R.id.button1);
openserial.setOnClickListener(newView.OnClickListener()
{

@Override
publicvoid onClick(View arg0)
{
//TODO Auto-generated method stub
try
{
classserialport=new SerialPort(new File("/dev/ttyS2"),9600);
}catch(SecurityExceptione)
{
e.printStackTrace();
}
catch(IOExceptione)
{
e.printStackTrace();
}
mInStream=(FileInputStream) classserialport.getInputStream();
Toast.makeText(MyserialActivity.this,"串口打開成功",Toast.LENGTH_SHORT).show();
}
});
/*
* 發送數據
* */
finalButton sendButton =(Button)findViewById(R.id.button2);
sendButton.setOnClickListener(newView.OnClickListener()
{

@Override
publicvoid onClick(View arg0)
{

Stringindata;
indata=sendedit.getText().toString();
//TODO Auto-generated method stub
try
{
mOutStream=(FileOutputStream) classserialport.getOutputStream();
mOutStream.write(indata.getBytes());
mOutStream.write(' ');
}
catch(IOExceptione)
{
e.printStackTrace();
}
Toast.makeText(MyserialActivity.this,"數據發送成功",Toast.LENGTH_SHORT).show();
sendedit.setText("");
}
});
/*
* 接收數據
* */
finalButton receButton= (Button)findViewById(R.id.button3);
receButton.setOnClickListener(newView.OnClickListener()
{//inttag =0;

@Override
publicvoid onClick(View arg0)
{
// TODO Auto-generated method stub
intsize;
try
{
byte[]buffer = new byte[64];
if(mInStream== null) return;
size= mInStream.read(buffer);
if(size>0)
{
receiveedit.setText("");

}
if(size>0)
{
onDataReceive(buffer,size);
}
inttag =1;

receiveedit.setText(newString(buffer, 0, size));

}catch(IOExceptione)
{
e.printStackTrace();
return;
}
}

privateboolean isInterrupted()
{
// TODO Auto-generated methodstub
returnfalse;
}
});
/*
* 清楚接收區
* */
finalButton ClearButton = (Button)findViewById(R.id.clear);
ClearButton.setOnClickListener(newView.OnClickListener()
{

@Override
publicvoid onClick(View arg0)
{
//TODO Auto-generated method stub
receiveedit.setText("");
}
});}

@Override
publicboolean onCreateOptionsMenu(Menu menu)
{
//Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.myserial,menu);
returntrue;
}

}

好吧 你做好了。

3需要載入的文件

下面我把所需要添加的代碼貼一貼

第一個是Serialport.java

/*
* Copyright 2009 Cedric Priscal
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package android.serialport;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.util.Log;

public class SerialPort {

private static final String TAG = "SerialPort";

/*
* Do not remove or rename the field mFd: it is used by native method close();
*/
private FileDescriptor mFd; //創建一個文件描述符對象 mFd
private FileInputStream mFileInputStream;
private FileOutputStream mFileOutputStream;

public SerialPort(File device, int baudrate) throws SecurityException, IOException {
/*
* 檢查訪問許可權
* */
/* Check access permission */
if (!device.canRead() || !device.canWrite()) {//如果設備不可讀或者設備不可寫
try {
/* Missing read/write permission, trying to chmod the file *///沒有讀寫許可權,就嘗試去掛載許可權
Process su; //流程進程 su
su = Runtime.getRuntime().exec("/system/bin/su");//通過執行掛載到/system/bin/su 獲得執行
String cmd = "chmod 777 " + device.getAbsolutePath() + " "
+ "exit ";
/*String cmd = "chmod 777 /dev/s3c_serial0" + " "
+ "exit ";*/
su.getOutputStream().write(cmd.getBytes());//進程。獲得輸出流。寫(命令。獲得二進制)
if ((su.waitFor() != 0) || !device.canRead()
|| !device.canWrite()) {//如果 進程等待不是0 或者 設備不能讀寫就
throw new SecurityException();//拋出一個許可權異常
}
} catch (Exception e) {
e.printStackTrace();
throw new SecurityException();
}
}
/*
*
* */
mFd = open(device.getAbsolutePath(), baudrate);
//device.getAbsolutePath()這是要掛載的路徑new File("/dev/ttyS2")
if (mFd == null) {
Log.e(TAG, "native open returns null");
throw new IOException();//輸入輸出異常
}
//將文件描述符 做輸入輸出流的參數 傳遞給創建的輸入輸出流
mFileInputStream = new FileInputStream(mFd);
mFileOutputStream = new FileOutputStream(mFd);
}

// Getters and setters
public InputStream getInputStream() {
return mFileInputStream;
}

public OutputStream getOutputStream() {
return mFileOutputStream;
}

// JNI
private native static FileDescriptor open(String path, int baudrate);
public native void close();
static {
System.loadLibrary("serial_port");
}
}

第二個是SerialPortFinder.java

/*
* Copyright 2009 Cedric Priscal
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package android.serialport;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.Iterator;
import java.util.Vector;

import android.util.Log;

public class SerialPortFinder {

/*
* 創建一個驅動程序類
* */
public class Driver {
public Driver(String name, String root) {
mDriverName = name;//String 類型的
mDeviceRoot = root;
}
private String mDriverName;
private String mDeviceRoot;
Vector<File> mDevices = null;
/*
* Vector 類在 java 中可以實現自動增長的對象數組
* 簡單的使用方法如下:
vector<int> test;//建立一個vector
test.push_back(1);
test.push_back(2);//把1和2壓入vector這樣test[0]就是1,test[1]就是2
* */
public Vector<File> getDevices() {
if (mDevices == null) {
mDevices = new Vector<File>();
File dev = new File("/dev");
File[] files = dev.listFiles();
int i;
for (i=0; i<files.length; i++) {
if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) {
Log.d(TAG, "Found new device: " + files[i]);
mDevices.add(files[i]);
}
}
}
return mDevices;
}

public String getName() {
return mDriverName;
}
}
/*
*
*
* */
private static final String TAG = "SerialPort";

private Vector<Driver> mDrivers = null;

Vector<Driver> getDrivers() throws IOException {
if (mDrivers == null) {
mDrivers = new Vector<Driver>();
LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));
String l;
while((l = r.readLine()) != null) {
String[] w = l.split(" +");
if ((w.length == 5) && (w[4].equals("serial"))) {
Log.d(TAG, "Found new driver: " + w[1]);
mDrivers.add(new Driver(w[0], w[1]));
}
}
r.close();
}
return mDrivers;
}

public String[] getAllDevices() {
Vector<String> devices = new Vector<String>();
// Parse each driver
Iterator<Driver> itdriv;
try {
itdriv = getDrivers().iterator();
while(itdriv.hasNext()) {
Driver driver = itdriv.next();
Iterator<File> itdev = driver.getDevices().iterator();
while(itdev.hasNext()) {
String device = itdev.next().getName();
String value = String.format("%s (%s)", device, driver.getName());
devices.add(value);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return devices.toArray(new String[devices.size()]);
}

public String[] getAllDevicesPath() {
Vector<String> devices = new Vector<String>();
// Parse each driver
Iterator<Driver> itdriv;
try {
itdriv = getDrivers().iterator();
while(itdriv.hasNext()) {
Driver driver = itdriv.next();
Iterator<File> itdev = driver.getDevices().iterator();
while(itdev.hasNext()) {
String device = itdev.next().getAbsolutePath();
devices.add(device);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return devices.toArray(new String[devices.size()]);
}
}

第三個是Android.mk

#
# Copyright 2009 Cedric Priscal
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

TARGET_PLATFORM := android-3
LOCAL_MODULE := serial_port
LOCAL_SRC_FILES := SerialPort.c
LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)

第四個是SerialPort.c

/*
* Copyright 2009 Cedric Priscal
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>

#include "android/log.h"
static const char *TAG="serial_port";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)

static speed_t getBaudrate(jint baudrate)
{
switch(baudrate) {
case 0: return B0;
case 50: return B50;
case 75: return B75;
case 110: return B110;
case 134: return B134;
case 150: return B150;
case 200: return B200;
case 300: return B300;
case 600: return B600;
case 1200: return B1200;
case 1800: return B1800;
case 2400: return B2400;
case 4800: return B4800;
case 9600: return B9600;
case 19200: return B19200;
case 38400: return B38400;
case 57600: return B57600;
case 115200: return B115200;
case 230400: return B230400;
case 460800: return B460800;
case 500000: return B500000;
case 576000: return B576000;
case 921600: return B921600;
case 1000000: return B1000000;
case 1152000: return B1152000;
case 1500000: return B1500000;
case 2000000: return B2000000;
case 2500000: return B2500000;
case 3000000: return B3000000;
case 3500000: return B3500000;
case 4000000: return B4000000;
default: return -1;
}
}

/*
* Class: cedric_serial_SerialPort
* Method: open
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT jobject JNICALL Java_android_serialport_SerialPort_open
(JNIEnv *env, jobject thiz, jstring path, jint baudrate)
{
int fd;
speed_t speed;
jobject mFileDescriptor;

/* Check arguments */
{
speed = getBaudrate(baudrate);
if (speed == -1) {
/* TODO: throw an exception */
LOGE("Invalid baudrate");
return NULL;
}
}

/* Opening device */
{
jboolean is;
const char *path_utf = (*env)->GetStringUTFChars(env, path, &is);
LOGD("Opening serial port %s", path_utf);
fd = open(path_utf, O_RDWR | O_DIRECT | O_SYNC);
LOGD("open() fd = %d", fd);
(*env)->ReleaseStringUTFChars(env, path, path_utf);
if (fd == -1)
{
/* Throw an exception */
LOGE("Cannot open port");
/* TODO: throw an exception */
return NULL;
}
}

/* Configure device */
{
struct termios cfg;
LOGD("Configuring serial port");
if (tcgetattr(fd, &cfg))
{
LOGE("tcgetattr() failed");
close(fd);
/* TODO: throw an exception */
return NULL;
}

cfmakeraw(&cfg);
cfsetispeed(&cfg, speed);
cfsetospeed(&cfg, speed);

if (tcsetattr(fd, TCSANOW, &cfg))
{
LOGE("tcsetattr() failed");
close(fd);
/* TODO: throw an exception */
return NULL;
}
}

/* Create a corresponding file descriptor */
{
jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");
jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");
jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
(*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);
}

return mFileDescriptor;
}

/*
* Class: cedric_serial_SerialPort
* Method: close
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_android_serialport_SerialPort_close
(JNIEnv *env, jobject thiz)
{
jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");

jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");

jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);

LOGD("close(fd = %d)", descriptor);
close(descriptor);
}

Ⅲ 如何編寫一個用於Android的音效驅動和控製程序

本教程將逐步講解從入門開始如何編寫一個可用於Android 4.0的音效驅動和控製程序(Android 2.3上只是部分介面不同而已)。對於Android操作系統的架構等將不再敘述。
軟體需求(Windows環境):
Windows操作系統、最新版Cygwin、Android NDK r8或更高、Eclipse、最新版Android SDK
專業技術需求:
掌握基本C/C++語法、掌握基本Java語法、基本Android UI設計、定點數學原理和演算法、基本音頻處理技術
可選高級技術需求:
IIR/FIR濾波器、FFT、Thumb/ARM匯編、NEON指令集

1、什麼是Android里的音效驅動,它是什麼架構。
從Android 2.3版開始,在系統多媒體框架里增加了一個SoundFX層,這個層就是「音效處理過程」。當多媒體系統運作時,框架允許將一個「標准」的SoundFX庫載入對應媒體流的Mixer處。SoundFX庫需要遵循OpenSLES架構,即所謂的標准就是實現一個基於OpenSLES架構的.so庫。
SoundFX可以被載入到任何一個音頻流上,每個音頻流使用會話ID作為標識符。注意:0表示系統總輸出的音頻流會話ID。一般情況下音效驅動就要載入到這個流上,才可以對系統內所有的聲音做處理(包括音視頻播放器、游戲、鈴聲等)。
同樣的,每一個SoundFX在載入時/後都有很多配置參數和控制權的優先順序。而完成對SoundFX的載入就需要一個控製程序。控製程序一般由Java語言在Eclipse中實現,通俗的說控製程序就是一個Android的apk程序。SoundFX可以理解為Windows系統里的底層混合器,控製程序可以理解為Windows的控制面板,在控制面板上控制SoundFX的載入和啟動,各個參數的設置等。當一個控製程序啟動後,它首先要做的事情就是按照OpenSLES框架來通知系統載入一個SoundFX到一個媒體流,然後通過UI交互來啟用/禁用該SoundFX,同時根據UI來控制SoundFX的參數,當退出時也需要通知系統卸載該SoundFX。

2、從哪開始?
因為Android規定SoundFX必須基於OpenSLES,所以最先要做的事情就是選擇一個效果器的類型。這是為什麼呢?到底是什麼意思呢?OpenSLES規定一個效果器要有兩個必須的條件,一個是該效果器的類型,一個是該效果器的唯一識別碼。這兩個東西在C/C++語言中是按照GUID結構體來存儲的(GUID是什麼?找度娘)。
其中類型的GUID是OpenSLES定死的,音量(SL_IID_VOLUME)、采樣率控制(SL_IID_PLAYBACKRATE)、均衡器(SL_IID_EQUALIZER)、預設混響(SL_IID_PRESETREVERB)、環境混響(SL_IID_ENVIRONMENTALREVERB)、3D定位(SL_IID_3DLOCATION)、多普勒效應(SL_IID_3DDOPPLER)、低音增強(SL_IID_BASSBOOST)、升降調(SL_IID_PITCH)、虛擬化(SL_IID_VIRTUALIZER)。這里沒有你想要的?你想自定義?什麼,你要做一個高音增強?無論做什麼,都得在這裡面選一個。為了簡單一點,那就選虛擬化吧,虛擬化只有一個固定參數。(這里沒看明白?那就把整個教程都看完,相信看到最後你會明白的)
下一步是生成一個自己獨一無二的GUID來給自己的SoundFX命名。生成的辦法有很多,有現成軟體也有網頁。這里我生成的是{42C6510E-1811-4857-8CA5-C204A8A3B0D4}。
以上提及的詳細內容和編程指導請閱讀Android NDK\platforms\android-14\arch-arm\usr\include\SLES\OpenSLES.h。(Android 4.0對應android

Ⅳ Android 重學系列 ion驅動源碼淺析

上一篇文章,在解析初始化GraphicBuffer中,遇到一個ion驅動,對圖元進行管理。首先看看ion是怎麼使用的:

我們按照這個流程分析ion的源碼。

如果對ion使用感興趣,可以去這篇文章下面看 https://blog.csdn.net/hexiaolong2009/article/details/102596744

本文基於Android的Linux內核版本3.1.8

遇到什麼問題歡迎來本文討論 https://www.jianshu.com/p/5fe57566691f

什麼是ion?如果是音視頻,Camera的工程師會對這個驅動比較熟悉。最早的GPU和其他驅動協作申請一塊內存進行繪制是使用比較粗暴的共享內存。在Android系統中使用的是匿名內存。最早由三星實現了一個Display和Camera共享內存的問題,曾經在Linux社區掀起過一段時間。之後各路大牛不斷的改進之下,就成為了dma_buf驅動。並在 Linux-3.3 主線版本合入主線。現在已經廣泛的運用到各大多媒體開發中。

首先介紹dma_buf的2個角色,importer和exporter。importer是dma_buf驅動中的圖元消費者,exporter是dma_buf驅動中的圖元生產者。

這里借用大佬的圖片:

ion是基於dma_buf設計完成的。經過閱讀源碼,其實不少思路和Android的匿名內存有點相似。閱讀本文之前就算不知道dma_buf的設計思想也沒關系,我不會仔細到每一行,我會注重其在gralloc服務中的申請流程,看看ion是如何管理共享內存,為什麼要拋棄ashmem。

我們先來看看ion的file_operation:

只有一個open和ioctl函數。但是沒有mmap映射。因此mmap映射的時候一定其他對象在工作。

我們關注顯卡英偉達的初始化模塊。
文件:/ drivers / staging / android / ion / tegra / tegra_ion.c

mole_platform_driver實際上就是我之前經常提到過的mole_init的一個宏,多了一個register注冊到對應名字的平台中的步驟。在這裡面注冊了一個probe方法指針,probe指向的tegra_ion_probe是載入內核模塊注冊的時候調用。

先來看看對應的結構體:

再來看看對應ion內的堆結構體:

完成的事情如下幾個步驟:

我們不關注debug模式。其實整個就是我們分析了很多次的方法。把這個對象注冊miscdevice中。等到insmod就會把整個整個內核模塊從dev_t的map中關聯出來。

我們來看看這個驅動結構體:

文件:/ drivers / staging / android / ion / ion_heap.c

這里有四個不同堆會申請出來,我們主要來看看默認的ION_HEAP_TYPE_SYSTEM對應的heap流程。

其實真正象徵ion的內存堆是下面這個結構體

不管原來的那個heap,會新建3個ion_system_heap,分別order為8,4,0,大於4為大內存。意思就是這個heap中持有一個ion_page_pool 頁資源池子,裡面只有對應order的2的次冪,內存塊。其實就和夥伴系統有點相似。

還會設置flag為ION_HEAP_FLAG_DEFER_FREE,這個標志位後面會用到。

文件:/ drivers / staging / android / ion / ion_page_pool.c

在pool中分為2個鏈表一個是high_items,另一個是low_items。他們之間的區分在此時就是以2為底4的次冪為分界線。

文件:/ drivers / staging / android / ion / ion.c

因為打開了標志位ION_HEAP_FLAG_DEFER_FREE和heap存在shrink方法。因此會初始化兩個回收函數。

文件:/ drivers / staging / android / ion / ion_heap.c

此時會創建一個內核線程,調用ion_heap_deferred_free內核不斷的循環處理。不過由於這個線程設置的是SCHED_IDLE,這是最低等級的時間片輪轉搶占。和Handler那個adle一樣的處理規則,就是閑時處理。

在這個循環中,不斷的循環銷毀處理heap的free_list裡面已經沒有用的ion_buffer緩沖對象。

文件:/ drivers / staging / android / ion / ion_system_heap.c

注冊了heap的銷毀內存的方法。當系統需要銷毀頁的時候,就會調用通過register_shrinker注冊進來的函數。

文件:/ drivers / staging / android / ion / ion_page_pool.c

整個流程很簡單,其實就是遍歷循環需要銷毀的頁面數量,接著如果是8的次冪就是移除high_items中的page緩存。4和0則銷毀low_items中的page緩存。至於為什麼是2的次冪其實很簡單,為了銷毀和申請簡單。__free_pages能夠整頁的銷毀。

文件:/ drivers / staging / android / ion / ion.c

主要就是初始化ion_client各個參數,最後把ion_client插入到ion_device的clients。來看看ion_client結構體:

核心還是調用ion_alloc申請一個ion緩沖區的句柄。最後把數據拷貝會用戶空間。

這個實際上就是找到最小能承載的大小,去申請內存。如果8kb申請內存,就會拆分積分在0-4kb,4kb-16kb,16kb-128kb區間找。剛好dma也是在128kb之內才能申請。超過這個數字就禁止申請。8kb就會拆成2個4kb保存在第一個pool中。

最後所有的申請的page都添加到pages集合中。

文件:/ drivers / staging / android / ion / ion_page_pool.c

能看到此時會從 ion_page_pool沖取出對應大小區域的空閑頁返回上層,如果最早的時候沒有則會調用ion_page_pool_alloc_pages申請一個新的page。由於引用最終來自ion_page_pool中,因此之後申請之後還是在ion_page_pool中。

這里的處理就是為了避免DMA直接內存造成的緩存差異(一般的申請,默認會帶一個DMA標志位)。換句話說,是否打開cache其實就是,關閉了則使用pool的cache,打開了則不使用pool緩存,只依賴DMA的緩存。

我們可以看另一個dma的heap,它是怎麼做到dma內存的一致性.
文件: drivers / staging / android / ion / ion_cma_heap.c

能看到它為了能辦到dma緩存的一致性,使用了dma_alloc_coherent創建了一個所有強制同步的地址,也就是沒有DMA緩存的地址。

這里出現了幾個新的結構體,sg_table和scatterlist

文件:/ lib / scatterlist.c

這裡面實際上做的事情就是一件:初始化sg_table.
sg_table中有一個核心的對象scatterlist鏈表。如果pages申請的對象數量<PAGE_SIZE/sizeof(scatterlist),每一項sg_table只有一個scatterlist。但是超出這個數字就會增加一個scatterlist。

用公式來說:

換句話說,每一次生成scatterlist的鏈表就會直接盡可能占滿一頁,讓內存更好管理。

返回了sg_table。

初始化ion_handle,並且記錄對應的ion_client是當前打開文件的進程,並且設置ion_buffer到handle中。使得句柄能夠和buffer關聯起來。

每當ion_buffer需要銷毀,

Ⅳ 如何寫一個Android USB介面驅動

說到 android 驅動是離不開 Linux 驅動的。Android 內核採用的是 Linux2.6 內核 (最近Linux 3.3 已經包含了一些 Android 代碼)。但 Android 並沒有完全照搬 Linux 系統內核,除了對Linux 進行部分修正,還增加了不少內容。android 驅動 主要分兩種類型:Android 專用驅動 和 Android 使用的設備驅動(linux)。
Android 專有驅動程序:
1)Android Ashmem 匿名共享內存; 為用戶空間程序提供分配內存的機制,為進程間提供大塊共享內存,同時為內核提供回收和管理這個內存。
2)Android Logger 輕量級的LOG(日誌) 驅動;
3)Android Binder 基於 OpenBinder 框架的一個驅動;
4)Android Power Management 電源管理模塊;
5)Low Memory Killer 低內存管理器;
6)Android PMEM 物理內存驅動;
7)USB Gadget USB 驅動(基於 gaeget 框架);
8)Ram Console 用於調試寫入日誌信息的設備;
9)Time Device 定時控制設備;
10)Android Alarm 硬體時鍾;

Android 上的設備驅動:
1)Framebuff 顯示驅動;
2)Event 輸入設備驅動;
3)ALSA 音頻驅動;
4)OSS 音頻驅動;
5)v412攝像頭:視頻驅動;
6)MTD 驅動;
7)藍牙驅動;
8)WLAN 設備驅動;
Android 專有驅動程序

1.Android Ashmem
為用戶空間程序提供分配內存的機制,為進程間提供大塊共享內存,同時為內核提供回收和管理這個內存。
設備節點:/dev/ashmen .主設備號 10.
源碼位置: include/linux/ashmen.h Kernel /mm/ashmen.c
相比於 malloc 和 anonymous/named mmap 等傳統的內存分配機制,其優勢是通過內核驅動提供了輔助內核的內存回收演算法機制(pin/unoin)
2.Android Logger
無論是底層的源代碼還上層的應用,我們都可以使用 logger 這個日誌設備看、來進行調試。
設備節點: /dev/log/main /dev/log/event /dev/log/radio
源碼位置:include/linux/logger.h include/linux/logger.c
3.Android Binder
IPC Binder 一種進程間通信機制。他的進程能夠為其它進程提供服務 ----- 通過標準的 Linux 系統調用 API。
設備節點 :/dev/binder
源碼位置:Kernel/include/linux/binder.h Kernel/drivers/misc/binder.c
4.Android Power Management
一個基於標准 linux 電源管理的輕量級 Android 電源管理系統,在 drivers/android/power.c kernel/power/
5.Low Memory Killer
它在用戶空間中指定了一組內存臨界值,當其中某個值與進程描述中的 oom_adj 值在同一范圍時,該進程將被Kill掉(在parameters/adj中指定oome_adj 的最小值)。它與標準的Linux OOM機制類似,只是實現方法不同
源碼位置:drivers/misc/lowmemorykiller.c
6.Android PMEM
PMEM 主要作用就是向用戶空間提供連續的物理內存區域。
1.讓 GPU 或 VPU 緩沖區共享 CPU 核心。
2.用於 Android service 堆。
源碼位置:include/linux/android_pmem.h drivers/android/pmem.c
7.USB Gadget
基於標准 Linux USB gaeget 驅動框架的設備驅動。
源碼位置:drivers/usb/gadet/
8.Ram Console
為了提供調試功能,android 允許將調試日誌信息寫入這個設備,它是基於 RAM 的 buffer.
源碼位置: drivers/staging/android/ram_console.c
9.Time Device
定時控制,提供了對設備進行定時控制的功能。
源碼位置:drivers/staging/android/timed_output.c(timed_gpio.c)
10.Android Alarm
提供一個定時器,用於把設備從睡眠狀態喚醒,同時它還提供了一個即使在設備睡眠時也會運行的時鍾基準。
設備節點:/dev/alarm
源碼位置:drivers/trc/alarm.c
Android 設備驅動
1. Framebuffer 幀緩存設備
Framebuffer 驅動在 Linux 中是標準的顯示設備的驅動。對於 PC 系統,它是顯卡的驅動 ; 對於嵌入式 SOC 處理器系統,它是 LCD 控制器或者其他顯示控制器的驅動。它是一個字元設備,在文件系統中設備節點通常是 /dev/fbx 。 每個系統可以有多個顯示設備 , 依次用 /dev/fbO 、 /dev/fb l
等來表示。在 Android 系統中主設備號為 29 ,次設備號遞增生成。
Android 對 Framebuffer 驅動的使用方式是標準的 , 在 / dev / graphie / 中的 Framebuffer 設備節點由 init 進程自動創建 , 被 libui 庫調用 。 Android 的 GUI 系統中 , 通過調用 Framebuffer 驅動的標准介面,實現顯示設備的抽象。

Framebuff的結構框架和實現 :

linux LCD驅動(二)--FrameBuffer

Linux LCD驅動(四)--驅動的實現
2.Event輸入設備驅動
Input 驅動程序是 Linux 輸入設備的驅動程序 , 分為游戲桿 (joystick) 、 滑鼠 (mouse 和 mice)和事件設備 (Event queue)3 種驅動程序。其中事件驅動程序是目前通用的程序,可支持鍵盤 、 滑鼠、觸摸屏等多種輸入設備。 Input 驅動程序的主設備號是 l3 ,每一種 Input 設備從設備號占 用5 位 , 3 種從設備號分配是 : 游戲桿 0 ~ 61 ; Mouse 滑鼠 33 ~ 62 ; Mice 滑鼠 63 ; 事件設備 64 ~ 95 ,各個具體的設備在 misc 、 touchscreen 、 keyboard 等目錄中。
Event 設備在用戶空問使用 read 、 ioctl 、 poll 等文件系統的介面操作, read 用於讀取輸入信息, ioctl 用於獲取和設置信息, poll 用於用戶空間的阻塞,當內核有按鍵等中斷時,通過在中斷中喚醒內核的 poll 實現。

Event 輸入驅動的架構和實現:
Linux設備驅動之——input子系統

3.ALSA音頻驅動
高級 Linux 聲音體系 ALSA(Advanced Linux Sound Architecture ) 是為音頻系統提供驅動 的Linux 內核組件,以替代原先的開發聲音系統 OSS 。它是一個完全開放源代碼的音頻驅動程序集 ,除了像 OSS 那樣提供一組內核驅動程序模塊之外 , ALSA 還專門為簡化應用程序的編寫提供相應的函數庫,與 OSS 提供的基於 ioctl 等原始編程介面相比, ALSA 函數庫使用起來要更加方便一些
利用該函數庫,開發人員可以方便、快捷地開發出自己的應用程序,細節則留給函數庫進行內部處理 。 所以雖然 ALSA 也提供了類似於 OSS 的系統介面 , 但建議應用程序開發者使用音頻函數庫,而不是直接調用驅動函數。
ALSA 驅動的主設備號為 116 ,次設備號由各個設備單獨定義,主要的設備節點如下:
/ dev / snd / contmlCX —— 主控制 ;
/ dev / snd / pcmXXXc —— PCM 數據通道 ;
/ dev / snd / seq —— 順序器;
/ dev / snd / timer —— 定義器。
在用戶空問中 , ALSA 驅動通常配合 ALsA 庫使用 , 庫通過 ioctl 等介面調用 ALSA 驅動程序的設備節點。對於 AIJSA 驅動的調用,調用的是用戶空間的 ALsA 庫的介面,而不是直接調用 ALSA 驅動程序。
ALSA 驅動程序的主要頭文件是 include / sound ./ sound . h ,驅動核心數據結構和具體驅動的注冊函數是 include / sound / core . h ,驅動程序 的核心實現是 Sound / core / sound . c 文件。
ALSA 驅動程序使用下面的函數注冊控制和設備:
int snd _ pcm _ new (struct snd _ card * card , char * id , int device , int playback _ count , int capture _ count , struct snd _ pcm ** rpcm) ;
int snd ctl _ add(struct snd _ card * card , struct snd _ kcontrol * kcontro1) ;
ALSA 音頻驅動在內核進行 menuconfig 配置時 , 配置選項為 「 Device Drivers 」 > 「 Sound c ard support 」 一 > 「 Advanced Linux Sound Architecture 」 。子選項包含了 Generic sound devices( 通用聲音設備 ) 、 ARM 體系結構支持,以及兼容 OSS 的幾個選項。 ALsA 音頻驅動配置對應的文件是sound / core / Kconfig 。
Android 沒有直接使用 ALSA 驅動,可以基於 A-LSA 驅動和 ALSA 庫實現 Android Audio 的硬體抽象層; ALSA 庫調用內核的 ALSA 驅動, Audio 的硬體抽象層調用 ALSA 庫。
4.OSS音頻驅動
OSS(Open Sound System開放聲音系統)是 linux 上最早出現的音效卡驅動。OSS 由一套完整的內核驅動程序模塊組成,可以為絕大多數音效卡提供統一的編程介面。
OSS 是字元設備,主設備號14,主要包括下面幾種設備文件:
1) /dev/sndstat
它是音效卡驅動程序提供的簡單介面,它通常是一個只讀文件,作用也只限於匯報音效卡的當前狀態。(用於檢測音效卡)
2)/dev/dsp
用於數字采樣和數字錄音的設備文件。對於音頻編程很重要。實現模擬信號和數字信號的轉換。

3)/dev/audio
類似於/dev/dsp,使用的是 mu-law 編碼方式。

4)/dev/mixer
用於多個信號組合或者疊加在一起,對於不同的音效卡來說,其混音器的作用可能各不相同。

5)/dev/sequencer
這個設備用來對音效卡內建的波表合成器進行操作,或者對 MIDI 匯流排上的樂器進行控制。
OSS 驅動所涉及的文件主要包括:
kernel/include/linux/soundcard.h
kernel/include/linux/sound.h 定義 OSS 驅動的次設備號和注冊函數
kernel/sound_core.c OSS核心實現部分
5.V4l2視頻驅動
V4L2是V4L的升級版本,為linux下視頻設備程序提供了一套介面規范。包括一套數據結構和底層V4L2驅動介面。V4L2提供了很多訪問介面,你可以根據具體需要選擇操作方法。需要注意的是,很少有驅動完全實現了所有的介面功能。所以在使用時需要參考驅動源碼,或仔細閱讀驅動提供者的使用說明。
V4L2的主設備號是81,次設備號:0~255,這些次設備號里也有好幾種設備(視頻設備、Radio設備、Teletext、VBI)。
V4L2的設備節點: /dev/videoX, /dev/vbiX and /dev/radioX
Android 設備驅動(下)

MTD 驅動
Flash 驅動通常使用 MTD (memory technology device ),內存技術設備。
MTD 的字元設備:
/dev/mtdX
主設備號 90.
MTD 的塊設備:
/dev/block/mtdblockX

主設備號 13.
MTD 驅動源碼

drivers/mtd/mtdcore.c:MTD核心,定義MTD原始設備
drivers/mtd/mtdchar.c:MTD字元設備
drivers/mtd/mtdblock.c:MTD塊設備
MTD 驅動程序是 Linux 下專門為嵌入式環境開發的新一類驅動程序。Linux 下的 MTD 驅動程序介面被劃分為用戶模塊和硬體模塊:
用戶模塊 提供從用戶空間直接使用的介面:原始字元訪問、原始塊訪問、FTL (Flash Transition Layer)和JFS(Journaled File System)。

硬體模塊 提供內存設備的物理訪問,但不直接使用它們,二十通過上述的用戶模塊來訪問。這些模塊提供了快閃記憶體上讀、寫和擦除等操作的實現。

藍牙驅動

在 Linux 中,藍牙設備驅動是網路設備,使用網路介面。
Android 的藍牙協議棧使用BlueZ實現來對GAP, SDP以及RFCOMM等應用規范的支持,並獲得了SIG認證。由於Bluez使用GPL授權, 所以Android 框架通過D-BUS IPC來與bluez的用戶空間代碼交互以避免使用未經授權的代碼。

藍牙協議部分頭文件:
include/net/bluetooth/hci_core.h
include/net/bluetooth/bluetooth.h
藍牙協議源代碼文件:
net/bluetooth/*
藍牙驅動程序部分的文件:
drivers/bluetooth/*

藍牙的驅動程序一般都通過標準的HCI控制實現。但根據硬體介面和初始化流程的不同,又存在一些差別。這類初始化動作一般是一些晶振頻率,波特率等基礎設置。比如CSR的晶元一般通過BCSP協議完成最初的初始化配置,再激活標准HCI控制流程。對Linux來說,一旦bluez可以使用HCI與晶元建立起通信(一般是hciattach + hciconfig),便可以利用其上的標准協議(SCO, L2CAP等),與藍牙通信,使其正常工作了。

WLAN 設備驅動(Wi-Fi)(比較復雜我面會專門寫個wifi分析)

在linux中,Wlan設備屬於網路設備,採用網路介面。
Wlan在用戶空間採用標準的socket介面進行控制。
WiFi協議部分頭文件:
include/net/wireless.h
WiFi協議部分源文件:
net/wireless/*
WiFi驅動程序部分:
drivers/net/wireless/*

Ⅵ android 下如何動態載入觸摸屏驅動

TP驅動實現
1 修改ProjectConfig.mk
修改mediatek\config\prj\ProjectConfig.mk下的CUSTOM_KERNEL_TOUCHPANEL
其值由GT818B改為msg2133

2 增加ms2133驅動文件夾
根據TP廠家提供的驅動,我們在\mediatek\custom\common\kernel\touchpanel增加msg2133觸摸屏驅動文件夾msg2133,並做下面一些簡單修改正常使用。

(1) Msg2133介面的初始化
1) CHIP_EN片選使能引腳
mt_set_gpio_mode(GPIO_CTP_MSG2133_EN_PIN,GPIO_CTP_MSG2133_EN_PIN_M_GPIO);
mt_set_gpio_dir(GPIO_CTP_MSG2133_EN_PIN,GPIO_DIR_OUT);
mt_set_gpio_out(GPIO_CTP_MSG2133_EN_PIN,GPIO_OUT_ONE);</span>
msg2133晶元使能引腳配置為GPIO模式、輸出高電平使能。

2) INT中斷引腳
mt_set_gpio_mode(GPIO_CTP_MSG2133_EINT_PIN,GPIO_CTP_MSG2133_EINT_PIN_M_EINT);
mt_set_gpio_dir(GPIO_CTP_MSG2133_EINT_PIN,GPIO_DIR_IN);
mt_set_gpio_pull_enable(GPIO_CTP_MSG2133_EINT_PIN,GPIO_PULL_ENABLE);
mt_set_gpio_pull_select(GPIO_CTP_MSG2133_EINT_PIN,GPIO_PULL_UP);</span>

配置為中斷模式、輸入、使能上下拉功能和設置為上拉。

(2) IIC地址
Msg2133的iic讀寫地址,我從數據手冊上沒有找到是如何確定這兩個地址的,驅動廠家在驅動代碼中提供,如果想要具體是怎麼確定的,可咨詢廠家。
#defineFW_ADDR_MSG21XX (0xC4>>1)
#defineFW_ADDR_MSG21XX_TP (0x4C>>1)//write,0x26
#defineFW_UPDATE_ADDR_MSG21XX (0x92>>1)//read,0x49</span>
(3) 增加TP的虛擬按鍵(virtual key)

要在TP上增加虛擬按鍵,需要在tp對應的頭文件添加下面的設置:

1) 定義TPD_HAVE_BUTTON
2) 定義TPD_BUTTON_HEIGHT、TPD_KEY_COUNT、TPD_KEYS和TPD_KEYS_DIM,分別用於定義button被識別的縱向坐標、虛擬按鍵個數、對應的功能鍵和每個功能鍵的坐標
#defineTPD_HAVE_BUTTON

#defineTPD_BUTTON_HEIGHT 800
#defineTPD_KEY_COUNT 4
#defineTPD_KEYS { KEY_BACK, KEY_SEARCH,KEY_MENU, KEY_HOMEPAGE }
#define TPD_KEYS_DIM {{200,900,10,10},{260,900,10,10},{40,900,10,10},{120,900,10,10}}</span>

其中,{200,900,10,10}對應了KEY_BACK的坐標, (200,900)是該key center的坐標,10是該鍵的寬度,10是該鍵的高度。

3) 根據顯示屏解析度修改相關的宏定義
#defineTPD_RES_X 480 // (320)
#defineTPD_RES_Y 800 //(480)</span>

把常用的實體按鍵(導航按鍵)映射到觸屏區域的快捷方式,不強制要求一定要有物理按鍵來支持用戶操作,這對開發全觸摸屏的產品非常有利。

Ⅶ android驅動怎麼用

把手機和電腦連接,並打開設備鉛敗神管理器枯鋒,你可以找到一個帶有黃色問號的未知設備
雙擊它,看看是不是你買得手機 的設備名稱 和製造商,如果是,那就是這個設備了
確定是這個驅動後,切換到驅動程序 選項卡中,有一個更新驅動按鈕,單擊後,選擇手動槐虧查找並安裝驅動,然後將路徑指向你下載的驅動文件夾中,OK。希望可以幫到你

閱讀全文

與android驅動例子相關的資料

熱點內容
程序員涉黃 瀏覽:698
maven編譯resources下的js 瀏覽:519
ubuntu文件移動命令 瀏覽:227
安卓i怎麼查找蘋果手機 瀏覽:949
雲伺服器宕機概率 瀏覽:229
在線買葯用什麼app知乎 瀏覽:813
ubuntu解壓xz文件 瀏覽:674
宏傑加密時電腦關機 瀏覽:388
自己寫單片機編譯器 瀏覽:598
單片機按鍵閃爍 瀏覽:380
為什麼icloud總是顯連接伺服器失敗 瀏覽:888
如何設置域控伺服器 瀏覽:738
想在上海租房子什麼app好 瀏覽:185
編譯程序各部分是必不可少的嗎 瀏覽:885
編程不超過十行 瀏覽:764
數電編譯器的作用 瀏覽:337
時間演算法與現在有什麼區別 瀏覽:164
7zip解壓後沒文件夾 瀏覽:904
為什麼安卓送玫瑰ios收不到 瀏覽:10
美篇文章加密是什麼意思 瀏覽:84