0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何在Android 10設(shè)備上通過App控制GPIO

2132110287 ? 來源:萬象奧科 ? 2024-07-22 17:59 ? 次閱讀

本文檔提供了在 Android 10 設(shè)備上通過應(yīng)用程序(App)控制通用輸入輸出(GPIO)的詳細(xì)指南。這涵蓋了從創(chuàng)建 gpio驅(qū)動(dòng)到App 配置 以及 SELinux 策略以允許特定訪問的所有必要步驟。

1.1驅(qū)動(dòng)實(shí)現(xiàn)

添加創(chuàng)建gpio控制驅(qū)動(dòng)bspkernelkernel4.14driversgpiogpio_led.c,并添加好對(duì)應(yīng)的Makfile編譯

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include  
#include
#include
#include
#include
#include
#include
#include
#include
#include


#define GPIO_HIGH _IO('L', 0)
#define GPIO_LOW _IO('L', 1)


#define LED_ON 1
#define LED_OFF 0
#define SIMPIE_LED_MAX 4


//============================== Upper interface value ==============================//
// 驅(qū)動(dòng)模塊名稱定義
#define MODULE_NAME "gpio_led"     // 驅(qū)動(dòng)模塊的名字
#define MISC_NAME "gpio_led_device"   // 用于注冊(cè)為“misc”設(shè)備的名字


// 模塊函數(shù)接口定義,供上層應(yīng)用調(diào)用的接口。通過MM_DEV_MAGIC區(qū)分不同系統(tǒng)接口,通過_IO()加上自己的編號(hào)作為接口number。
#define MM_DEV_MAGIC 'N'


// LED 控制命令
#define RFID_IO1 _IO(MM_DEV_MAGIC, 93)
#define RFID_IO2 _IO(MM_DEV_MAGIC, 130)
#define RFID_IO3 _IO(MM_DEV_MAGIC, 121)
#define RFID_LED _IO(MM_DEV_MAGIC, 138)


static int major;
static struct class *cls;


// GPIO 描述數(shù)組
struct gpio_desc *led_gpio[SIMPIE_LED_MAX];


// cat命令將調(diào)用該函數(shù)
static ssize_t gpio_value_show(struct device *dev, struct device_attribute *attr, char *buf)
{
  return sprintf(buf, "%d
", gpiod_get_value(led_gpio[0]));
}


// echo命令將調(diào)用該函數(shù)
static ssize_t gpio_value_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)
{
  pr_err("[vanxoak]%c
", buf[0]);
  if ('0' == buf[0])
  {
    gpiod_direction_output(led_gpio[0], 0);
    pr_err("[vanxoak]: _%s_ :gpio off
", __func__);
  }
  else if ('1' == buf[0])
  {
    gpiod_direction_output(led_gpio[0], 1);
    pr_err("[vanxoak]: _%s_ :gpio on
", __func__);
  }
  else
    pr_err("I only support 0 or 1 to ctrl gpio on or off
");
  pr_err("[vanxoak]gpio_value_store
");
  return len;
}


// 定義一個(gè)名為gpio_led的設(shè)備屬性
static DEVICE_ATTR(gpio_led, 0664, gpio_value_show, gpio_value_store);


// 提供給上層控制的接口
long gpio_led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
  switch (cmd)
  {
  case RFID_LED:
    gpiod_direction_output(led_gpio[0], arg);
    break;
  case RFID_IO1:
    gpiod_direction_output(led_gpio[1], arg);
    break;
  case RFID_IO2:
    gpiod_direction_output(led_gpio[2], arg);
    break;
  case RFID_IO3:
    gpiod_direction_output(led_gpio[3], arg);
    break;


  default:
    pr_err("[vanxoak] %s default: break
", __func__);
    break;  
  }
  return 0;
}


struct file_operations gpio_led_ops = {
  .owner = THIS_MODULE,
  .unlocked_ioctl = gpio_led_ioctl,
};


// LED燈初始化
static int simpie_led_init(struct platform_device *pdev)
{
  int ret = 0;
  int i;


  // 申請(qǐng)gpio設(shè)備
  led_gpio[0] = devm_gpiod_get(&pdev->dev, "led0", GPIOD_OUT_LOW);
  led_gpio[1] = devm_gpiod_get(&pdev->dev, "led1", GPIOD_OUT_LOW);
  led_gpio[2] = devm_gpiod_get(&pdev->dev, "led2", GPIOD_OUT_LOW);
  led_gpio[3] = devm_gpiod_get(&pdev->dev, "led3", GPIOD_OUT_LOW);


  for (i = 0; i < SIMPIE_LED_MAX; i++)
 ? ?{
 ? ? ? ?if (IS_ERR(led_gpio[i]))
 ? ? ? ?{
 ? ? ? ? ? ?ret = PTR_ERR(led_gpio[i]);
 ? ? ? ? ? ?return ret;
 ? ? ? ?}
 ? ? ? ?// 輸出初始電平
 ? ? ? ?ret = gpiod_direction_output(led_gpio[i], LED_OFF);
 ? ?}


 ? ?device_create_file(&pdev->dev, &dev_attr_gpio_led);
  return ret;
}


// 驅(qū)動(dòng)入口
static int gpio_led_probe(struct platform_device *pdev)
{
  int ret = 0;
  pr_err("[vanxoak]gpio_led_probe start...
");


  // LED燈gpio初始化及輸出配置
  ret = simpie_led_init(pdev);  


  pr_err("[vanxoak]gpio_led_probe end...
");


  return 0;
}


// 綁定設(shè)備
static struct of_device_id gpio_led_match_table[] = {
  {.compatible = "yz,gpio-led"},
  {}};


static int gpio_led_remove(struct platform_device *pdev)
{
  pr_err("[vanxoak]gpio_led_remove...
");
  return 0;
}


static struct platform_driver gpio_led_driver = {
  .driver = {
    .name = MODULE_NAME,
    .owner = THIS_MODULE,
    .of_match_table = gpio_led_match_table,
  },
  .probe = gpio_led_probe,
  .remove = gpio_led_remove,
};


// gpio初始化入口
static int gpio_led_init(void)
{
  struct device *mydev;


  pr_err("[vanxoak]gpio_led_init start...
");
  platform_driver_register(&gpio_led_driver);


  major = register_chrdev(0, "gpiotest", &gpio_led_ops);


  // 創(chuàng)建gpio_led_class設(shè)備
  cls = class_create(THIS_MODULE, "gpio_led_class");


  // 在gpio_led_class設(shè)備目錄下創(chuàng)建一個(gè)gpio_led_device屬性文件
  mydev = device_create(cls, 0, MKDEV(major, 0), NULL, MISC_NAME);
  if (sysfs_create_file(&(mydev->kobj), &dev_attr_gpio_led.attr))
  {  
    return -1;
  }


  return 0;
}


static void gpio_led_exit(void)
{
  pr_err("[vanxoak]gpio_led_exit...
");
  platform_driver_unregister(&gpio_led_driver);


  device_destroy(cls, MKDEV(major, 0));
  class_destroy(cls);
  unregister_chrdev(major, "gpiotest");
}


module_init(gpio_led_init);
module_exit(gpio_led_exit);


MODULE_DESCRIPTION("Device_create Driver");
MODULE_LICENSE("GPL");


設(shè)備樹配置 
gpio_led: yz,gpio-led {
        status = "disabled";
        compatible = "yz,gpio-led";
        led0-gpio = <&ap_gpio 138 GPIO_ACTIVE_HIGH>;
        led1-gpio = <&ap_gpio 93 GPIO_ACTIVE_HIGH>;
        led2-gpio = <&ap_gpio 130 GPIO_ACTIVE_HIGH>;
        led3-gpio = <&ap_gpio 121 GPIO_ACTIVE_HIGH>;
};

配置好上面gpio驅(qū)動(dòng)后重新編譯更新kernel 可以在/dev目錄下找到對(duì)應(yīng)的設(shè)備文件

"/dev/gpio_led_device",通過讀寫設(shè)備文件就可以操作gpio了。

1.2創(chuàng)建 Native 庫

1.2.1設(shè)置 JNI 方法

在 App 中定義 JNI 方法以實(shí)現(xiàn)與 GPIO 設(shè)備的交互。

public class NativeClass {     






  static {     
    try {     
      System.loadLibrary("jni_gpiocontrol");     
      Log.d("NativeClass", "Native library loaded successfully.");     
    } catch (UnsatisfiedLinkError e) {     
      Log.e("NativeClass", "Failed to load native library: " + e.getMessage());     
      // throw new RuntimeException("Failed to load native library", e);     
    }     
  }     
  // 聲明本地方法     
  public native int controlGPIO(int cmd, long arg);     
}

1.2.2實(shí)現(xiàn) Native 方法

在app/src/main目錄下創(chuàng)建一個(gè)cpp文件夾(如果你的項(xiàng)目是用Kotlin編寫的,這個(gè)步驟仍然適用,因?yàn)镴NI是用C/C++實(shí)現(xiàn)的)。將你的libjni_gpiocontrol.cpp文件放到這個(gè)cpp目錄中。

注意事項(xiàng):確保本地方法簽名正確,Java方法簽名和本地(C/C++)方法實(shí)現(xiàn)之間必須完全匹配。

#include
#include
#include
#include
#include
#include
#include
#include


#define MM_DEV_MAGIC 'N'
#define RFID_LED _IO(MM_DEV_MAGIC, 138)
#define RFID_IO1 _IO(MM_DEV_MAGIC, 93)
#define RFID_IO2 _IO(MM_DEV_MAGIC, 130)
#define RFID_IO3 _IO(MM_DEV_MAGIC, 121)  


#define DEVICE_PATH "/dev/gpio_led_device"
#define LOG_TAG "GPIOControl"




extern "C" JNIEXPORT jint JNICALL
Java_com_example_gpio_NativeClass_controlGPIO(JNIEnv *env, jobject obj, jint cmd, jlong arg) {


  int device_fd;
  long ioctl_result;
  unsigned int ioctl_cmd = cmd;


  // Open the device file
  device_fd = open(DEVICE_PATH, O_RDWR);
  if (device_fd < 0) {
 ? ? ? ?__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Could not open device: %s", strerror(errno));
 ? ? ? ?return -1;
 ? ?}


 ? ?// Translate cmd to appropriate ioctl command based on input
 ? ?switch (cmd) {
 ? ? ? ?case 138:
 ? ? ? ? ? ?ioctl_cmd = RFID_LED;
 ? ? ? ? ? ?break;
 ? ? ? ?case 93:
 ? ? ? ? ? ?ioctl_cmd = RFID_IO1;
 ? ? ? ? ? ?break;
 ? ? ? ?case 130:
 ? ? ? ? ? ?ioctl_cmd = RFID_IO2;
 ? ? ? ? ? ?break;
 ? ? ? ?case 121:
 ? ? ? ? ? ?ioctl_cmd = RFID_IO3;
 ? ? ? ? ? ?break;
 ? ? ? ?default:
 ? ? ? ? ? ?__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Invalid command");
 ? ? ? ? ? ?close(device_fd);
 ? ? ? ? ? ?return -1;
 ? ?}


 ? ?// Send an ioctl to the device
 ? ?ioctl_result = ioctl(device_fd, ioctl_cmd, arg);
 ? ?if (ioctl_result < 0) {
 ? ? ? ?__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Failed to call ioctl: %s", strerror(errno)); ? ?
 ? ? ? ?close(device_fd);
 ? ? ? ?return -1;
 ? ?}


 ? ?// Close the device
 ? ?close(device_fd);


 ? ?return 0;
}

1.2.3編譯 Native 庫

使用 CMake 或 ndk-build 工具編譯你的 native 代碼為共享庫(.so 文件)。

添加appsrcmaincppCMakeLists.txt

cmake_minimum_required(VERSION 3.4.1)
project("gpiotest")
add_library(jni_gpiocontrol SHARED libjni_gpiocontrol.cpp)




find_library( log-lib log )


target_link_libraries(jni_gpiocontrol
            ${log-lib} ) 

1.2.4調(diào)用 Native 方法

通過 JNI 接口在 App 中調(diào)用實(shí)現(xiàn)的 native 方法以控制 GPIO。

public class MainActivity extends AppCompatActivity {
  private NativeClass nativeClass;


  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    nativeClass = new NativeClass();


    // 示例:打開LED  
    int result = nativeClass.controlGPIO(138, 1);
    // 根據(jù)result處理結(jié)果
  }
}

2.SELinux 配置

由于直接訪問硬件設(shè)備在 Android 中受到 SELinux 策略的限制,需要修改 SELinux 策略以允許 App 訪問 GPIO 設(shè)備文件。

定義設(shè)備類型:為 GPIO 設(shè)備定義一個(gè)新的 SELinux 類型(如 gpio_led_device_t)。

SDK_dir/device/sprd/sharkle/common/sepolicy/device.te 添加

# 定義新的設(shè)備類型
type gpio_led_device_t, dev_type;

分配文件上下文:為 GPIO 設(shè)備文件分配新定義的 SELinux 類型。

SDK_dir/device/sprd/sharkle/common/sepolicy/file_contexts中添加

/dev/gpio_led_device ugpio_led_device_t:s0

授予權(quán)限:在 SELinux 策略中添加規(guī)則,允許 App 訪問 GPIO 設(shè)備。

SDK_dir/device/sprd/sharkle/common/sepolicy/system_app.te

# 允許 system_app 訪問 gpio_led_device
allow system_app gpio_led_device_t:chr_file { read write };

重新編譯 SELinux 策略:對(duì)更改的 SELinux 策略進(jìn)行編譯,并將其部署到設(shè)備上。這一步驟的目的是將自定義的安全策略更改應(yīng)用到Android構(gòu)建系統(tǒng)的預(yù)設(shè)SELinux策略中,確保在編譯系統(tǒng)鏡像時(shí),這些更改會(huì)被包含進(jìn)去。

cp system/sepolicy/public/app.te system/sepolicy/prebuilts/api/29.0/public/app.te
cp system/sepolicy/private/coredomain.te system/sepolicy/prebuilts/api/29.0/private/coredomain.te

3.測(cè)試與部署

測(cè)試 App:在具有所需硬件支持的 Android 10 設(shè)備上測(cè)試 App。確保 App 能成功加載 native 庫,并能通過 JNI 調(diào)用控制 GPIO。

SELinux 策略測(cè)試:驗(yàn)證 SELinux 策略更改是否允許 App 無障礙地訪問 GPIO 設(shè)備。

問題排查:如果遇到訪問被拒絕的情況,請(qǐng)檢查 SELinux 審計(jì)日志以確定是否需要進(jìn)一步調(diào)整策略。

3.1注意事項(xiàng)

安全性:在修改 SELinux 策略以增加訪問權(quán)限時(shí),務(wù)必小心謹(jǐn)慎,避免引入安全漏洞。

設(shè)備兼容性:確保你的實(shí)現(xiàn)考慮到了不同設(shè)備可能存在的硬件和配置差異。

文檔和維護(hù):適當(dāng)記錄你的設(shè)計(jì)和實(shí)現(xiàn)過程,包括 JNI 接口、native 代碼和 SELinux 策略更改,以便于未來的審計(jì)和維護(hù)。

通過遵循以上步驟,你可以在遵守 Android 安全模型的同時(shí),實(shí)現(xiàn) App 對(duì) GPIO 的有效控制。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • APP
    APP
    +關(guān)注

    關(guān)注

    33

    文章

    1561

    瀏覽量

    72265
  • 編譯
    +關(guān)注

    關(guān)注

    0

    文章

    646

    瀏覽量

    32737
  • GPIO
    +關(guān)注

    關(guān)注

    16

    文章

    1181

    瀏覽量

    51735

原文標(biāo)題:如何以JNI方式實(shí)現(xiàn)安卓APP控制GPIO?

文章出處:【微信號(hào):萬象奧科,微信公眾號(hào):萬象奧科】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Android移動(dòng)設(shè)備應(yīng)用機(jī)器學(xué)習(xí)

    我們考慮了如何在 Android 操作系統(tǒng)中使用預(yù)訓(xùn)練的圖像分類模型。此外,模型的使用也可以在嵌入式設(shè)備使用,因?yàn)?TensorFlow Lite 解釋器還具有 C++ 接口并占用約
    發(fā)表于 07-09 07:20 ?1243次閱讀

    CC2650讀取Android app顯示的服務(wù)問題

    CC2650讀取Android app顯示的服務(wù)問題這個(gè)是CC2650板子跑HeartRate時(shí),APP顯示的服務(wù),并沒有 HEARTR
    發(fā)表于 04-07 11:09

    如何使用核心模塊開發(fā)設(shè)備控制功能(iOS APP開發(fā))

    Android Demo 示例源碼,包含了設(shè)備網(wǎng)絡(luò)配置、用戶注冊(cè)登錄、設(shè)備狀態(tài)查詢、設(shè)備遠(yuǎn)程控制等功能的參考實(shí)現(xiàn),開發(fā)者可
    發(fā)表于 11-29 18:18

    牛掰了!鴻蒙與Android完美融合,將鴻蒙設(shè)備當(dāng)Android設(shè)備

    并不能分辨哪一個(gè)是Android App,哪一個(gè)是HarmonyOS App,所以HarmonyOS真正做到了兩套系統(tǒng)無縫切換,用戶完全感覺不到。3.用adb命令行控制HarmonyO
    發(fā)表于 11-13 09:44

    如何通過APP控制串口屏和GPIO口的電平

    簡(jiǎn)介:本文將通過介紹如何實(shí)現(xiàn)屏和App實(shí)時(shí)顯示溫濕度和光照度采集數(shù)據(jù),以及通過控制屏和App控制
    發(fā)表于 02-21 06:51

    如何通過kernel設(shè)備文件節(jié)點(diǎn)打通android app與kernel間的通信?

    如何通過kernel設(shè)備文件節(jié)點(diǎn)打通android app與kernel間的通信?
    發(fā)表于 03-04 06:10

    如何通過kernel設(shè)備文件節(jié)點(diǎn)打通android app與kernel間的通信?

    如何通過kernel設(shè)備文件節(jié)點(diǎn)打通android app與kernel間的通信?
    發(fā)表于 03-04 06:40

    請(qǐng)問如何在Android 9以上的設(shè)備正常使用這個(gè)功能?

    請(qǐng)問如何在Android 9以上的設(shè)備正常使用這個(gè)功能?好像是https或者h(yuǎn)ttp引起的。 謝謝
    發(fā)表于 05-25 08:30

    Android設(shè)備通過藍(lán)牙模塊實(shí)現(xiàn)無線終端的設(shè)計(jì)

    的RISC 內(nèi)核的ATMEGA 8 為核心,并集成藍(lán)牙串行模塊為通信信道。Android 設(shè)備通過藍(lán)牙將數(shù)據(jù)發(fā)送至下位機(jī),下位機(jī)根據(jù)接收到數(shù)據(jù),完成相應(yīng)的控制功能,并將處理結(jié)果上傳,實(shí)
    的頭像 發(fā)表于 07-11 08:10 ?3216次閱讀
    <b class='flag-5'>Android</b><b class='flag-5'>設(shè)備</b><b class='flag-5'>通過</b>藍(lán)牙模塊實(shí)現(xiàn)無線終端的設(shè)計(jì)

    何在嵌入式Linux中使用GPIO

    了解如何在嵌入式Linux中使用GPIO,特別強(qiáng)調(diào)Zynq-7000系列。 我們介紹了基本的用戶和內(nèi)核空間GPIO使用情況,以及GPIO,GPIO
    的頭像 發(fā)表于 11-26 07:02 ?4024次閱讀

    未來Windows 10將會(huì)原生運(yùn)行Android App?

    11月30日早間消息,據(jù)外媒Windows Central 報(bào)道,微軟內(nèi)部正在開發(fā)內(nèi)部代號(hào)為“Latte”的新項(xiàng)目,這個(gè)項(xiàng)目將允許應(yīng)用程序開發(fā)人員將他們Android 應(yīng)用程序帶到Windows 10,也就是說未來Windows 10
    的頭像 發(fā)表于 11-30 10:28 ?1482次閱讀

    Android: 使用Linux regulator系統(tǒng)通過一個(gè)GPIO控制外部IC的電源

    Android: 使用Linux regulator系統(tǒng)通過一個(gè)GPIO控制外部IC的電源一、通過一個(gè)G
    發(fā)表于 01-06 16:41 ?0次下載
    <b class='flag-5'>Android</b>: 使用Linux regulator系統(tǒng)<b class='flag-5'>通過</b>一個(gè)<b class='flag-5'>GPIO</b><b class='flag-5'>控制</b>外部IC的電源

    何在STM8S控制執(zhí)行通用GPIO功能實(shí)現(xiàn)LED閃爍

    在本教程中,我們將學(xué)習(xí)如何在 STM8S 控制執(zhí)行通用 GPIO 功能。該板已經(jīng)有一個(gè)連接到端口 B 的引腳 5 的板載 LED,我們將學(xué)習(xí)如何使該 LED 閃爍,并添加一個(gè)外部
    的頭像 發(fā)表于 08-11 17:04 ?5371次閱讀
    如<b class='flag-5'>何在</b>STM8S<b class='flag-5'>控制</b>器<b class='flag-5'>上</b>執(zhí)行通用<b class='flag-5'>GPIO</b>功能實(shí)現(xiàn)LED閃爍

    Arduino/Android藍(lán)牙伺服電機(jī)控制安卓APP

    電子發(fā)燒友網(wǎng)站提供《Arduino/Android藍(lán)牙伺服電機(jī)控制安卓APP.zip》資料免費(fèi)下載
    發(fā)表于 12-05 09:14 ?4次下載
    Arduino/<b class='flag-5'>Android</b>藍(lán)牙伺服電機(jī)<b class='flag-5'>控制</b>安卓<b class='flag-5'>APP</b>

    通過WiFi使用Android設(shè)備控制機(jī)器人汽車

    電子發(fā)燒友網(wǎng)站提供《通過WiFi使用Android設(shè)備控制機(jī)器人汽車.zip》資料免費(fèi)下載
    發(fā)表于 01-03 14:02 ?0次下載
    <b class='flag-5'>通過</b>WiFi使用<b class='flag-5'>Android</b><b class='flag-5'>設(shè)備</b><b class='flag-5'>控制</b>機(jī)器人汽車