Android GPIO 控制方案
此方案實現Android APP控制CPU GPIO,支援設定IO方向、輸出、輸入、按鍵功能。
移植驅動與Framework gpio service
API呼叫方法
方法1 依賴Framework jar包(不推薦)
-
引入Android定製後的Framework jar包,out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar
- 將classes.jar拷貝到app/libs/目錄下
- 修改專案根目錄build.gradle,在allprojects段內增加下面程式碼:
allprojects { repositories { google() jcenter() } gradle.projectsEvaluated { tasks.withType(JavaCompile) { options.compilerArgs.add('-Xbootclasspath/p:app\\libs\\classes.jar') } } }
- 修改app/build.gradle,如下:
android{ defaultConfig { multiDexEnabled true } } dependencies { compileOnly files('libs/classes.jar') } preBuild { doLast { def imlFile = file(project.name + ".iml") println('Change ' + project.name + '.iml order') try { def parsedXml = (new XmlParser()).parse(imlFile) def jdkNode = parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' } parsedXml.component[1].remove(jdkNode) def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform" new groovy.util.Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK']) groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile)) } catch (FileNotFoundException e) { // nop, iml not found } } }
- 呼叫
SystemGpio gpioService = (SystemGpio) context.getSystemService("gpio");
方法二 反射呼叫(==推薦==)
- 在APP原始碼src/main目錄下新建aidl/android/os/這樣的目錄結構
- 在aidl/android/os/目錄下新建IGpioService.aidl檔案,內容如下:
package android.os; /** {@hide} */ interface IGpioService { int gpioWrite(int gpio, int value); int gpioRead(int gpio); int gpioDirection(int gpio, int direction, int value); int gpioRegKeyEvent(int gpio); int gpioUnregKeyEvent(int gpio); int gpioGetNumber(); }
- 反射呼叫
Method method = null; try { method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class); IBinder binder = (IBinder) method.invoke(null, new Object[]{"gpio"}); IGpioService gpioService = IGpioService.Stub.asInterface(binder); } catch (Exception e) { e.printStackTrace(); }
API使用說明
獲取GPIO數量
在使用GPIO前建議先獲取GPIO數量,當呼叫其它方法需要傳入引數“gpio”時可以使用0~Number之間的值。
如:gpioGetNumber()返回7,說明一共有7個GPIO,那麼傳入引數可以為:0、1、2、3、4、5、6。
/** * Get GPIO number * @return <0: error other: GPIO number */ public int gpioGetNumber() { if (null != mGpioService) { return mGpioService.gpioGetNumber(); } return -1; }
設定輸入輸出模式
/** * GPIO direction * @param gpio 0~Number * @param direction 0: input 1: output * @param value 0: Low 1: High */ public void gpioDirection(int gpio, int direction, int value) { if (null != mGpioService) { mGpioService.gpioDirection(gpio, direction, value); } }
控制GPIO輸出
/** * GPIO write * @param gpio 0~Number * @param value 0: Low 1: High */ public void gpioWrite(int gpio, int value) { if (null != mGpioService) { mGpioService.gpioWrite(gpio, value); } }
控制GPIO輸入
/** * GPIO read * @param gpio 0~Number * @return 0: Low 1: High other:error */ public int gpioRead(int gpio) { if (null != mGpioService) { return mGpioService.gpioRead(gpio); } return -1; }
設定GPIO為按鍵模式
/** * GPIO register key event * @param gpio 0~Number */ public void gpioRegKeyEvent(int gpio) { if (null != mGpioService) { mGpioService.gpioRegKeyEvent(gpio); } }
設定為按鍵模式後,當GPIO有電平翻轉時會上報按鍵事件,GPIO與KeyCode對應關係如下:
GPIO_0KeyEvent.KEYCODE_GPIO_0 GPIO_1KeyEvent.KEYCODE_GPIO_1 GPIO_2KeyEvent.KEYCODE_GPIO_2 GPIO_3KeyEvent.KEYCODE_GPIO_3 GPIO_4KeyEvent.KEYCODE_GPIO_4 GPIO_5KeyEvent.KEYCODE_GPIO_5 GPIO_6KeyEvent.KEYCODE_GPIO_6 GPIO_7KeyEvent.KEYCODE_GPIO_7 GPIO_8KeyEvent.KEYCODE_GPIO_8 GPIO_9KeyEvent.KEYCODE_GPIO_9
- 當GPIO變為低電平將上報:KeyEvent.ACTION_DOWN
- 當GPIO變為高電平將上報:KeyEvent.ACTION_UP
如果要取消按鍵模式則呼叫如下方法:
/** * GPIO unregister key event * @param gpio 0~Number */ public void gpioUnregKeyEvent(int gpio) { if (null != mGpioService) { mGpioService.gpioUnregKeyEvent(gpio); } }
例
依賴Framework jar方式參考原始碼:
package com.ayst.item; import android.annotation.SuppressLint; import android.content.Context; import android.os.SystemGpio; /** * Created by Administrator on 2018/11/6. */ public class GpioTest { private SystemGpio mGpioService; @SuppressLint("WrongConstant") public GpioTest(Context context) { mGpioService = (SystemGpio) context.getSystemService("gpio"); } /** * GPIO write * @param gpio 0~Number * @param value 0: Low 1: High */ public void gpioWrite(int gpio, int value) { if (null != mGpioService) { mGpioService.gpioWrite(gpio, value); } } /** * GPIO read * @param gpio 0~Number * @return 0: Low 1: High other:error */ public int gpioRead(int gpio) { if (null != mGpioService) { return mGpioService.gpioRead(gpio); } return -1; } /** * GPIO direction * @param gpio 0~Number * @param direction 0: input 1: output * @param value 0: Low 1: High */ public void gpioDirection(int gpio, int direction, int value) { if (null != mGpioService) { mGpioService.gpioDirection(gpio, direction, value); } } /** * GPIO register key event * @param gpio 0~Number */ public void gpioRegKeyEvent(int gpio) { if (null != mGpioService) { mGpioService.gpioRegKeyEvent(gpio); } } /** * GPIO unregister key event * @param gpio 0~Number */ public void gpioUnregKeyEvent(int gpio) { if (null != mGpioService) { mGpioService.gpioUnregKeyEvent(gpio); } } /** * Get GPIO number * @return <0: error other: GPIO number */ public int gpioGetNumber() { if (null != mGpioService) { return mGpioService.gpioGetNumber(); } return -1; } }
反射方式參考原始碼:
package com.ayst.item; import android.annotation.SuppressLint; import android.content.Context; import android.os.IBinder; import android.os.IGpioService; import android.os.RemoteException; import java.lang.reflect.Method; /** * Created by Administrator on 2018/11/6. */ public class GpioTest { private IGpioService mGpioService; @SuppressLint("WrongConstant") public GpioTest(Context context) { Method method = null; try { method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class); IBinder binder = (IBinder) method.invoke(null, new Object[]{"gpio"}); mGpioService = IGpioService.Stub.asInterface(binder); } catch (Exception e) { e.printStackTrace(); } } /** * GPIO write * * @param gpio0~Number * @param value 0: Low 1: High */ public void gpioWrite(int gpio, int value) { if (null != mGpioService) { try { mGpioService.gpioWrite(gpio, value); } catch (RemoteException e) { e.printStackTrace(); } } } /** * GPIO read * * @param gpio 0~Number * @return 0: Low 1: High other:error */ public int gpioRead(int gpio) { if (null != mGpioService) { try { return mGpioService.gpioRead(gpio); } catch (RemoteException e) { e.printStackTrace(); } } return -1; } /** * GPIO direction * * @param gpio0~Number * @param direction 0: input 1: output * @param value0: Low 1: High */ public void gpioDirection(int gpio, int direction, int value) { if (null != mGpioService) { try { mGpioService.gpioDirection(gpio, direction, value); } catch (RemoteException e) { e.printStackTrace(); } } } /** * GPIO register key event * * @param gpio 0~Number */ public void gpioRegKeyEvent(int gpio) { if (null != mGpioService) { try { mGpioService.gpioRegKeyEvent(gpio); } catch (RemoteException e) { e.printStackTrace(); } } } /** * GPIO unregister key event * * @param gpio 0~Number */ public void gpioUnregKeyEvent(int gpio) { if (null != mGpioService) { try { mGpioService.gpioUnregKeyEvent(gpio); } catch (RemoteException e) { e.printStackTrace(); } } } /** * Get GPIO number * * @return <0: error other: GPIO number */ public int gpioGetNumber() { if (null != mGpioService) { try { return mGpioService.gpioGetNumber(); } catch (RemoteException e) { e.printStackTrace(); } } return -1; } }