android jni控制gpio (rk3288)

  1.添加驱动程序  

  2.编写jni c程序编译为库给java调用  

  3.app调用jni静态链接库操作底层驱动

 

 1.添加驱动程序

 修改/work/rk3288/firefly-rk3288_android5.1_git_20180126/kernel/drivers/Makefile
    添加一行obj-y     += carroll/
    
    将carroll文件夹添加至此目录下/work/rk3288/firefly-rk3288_android5.1_git_20180126/kernel/drivers/
    文件夹包含驱动源码及Makefile
    # carroll
    obj-y        = test_led.o
    

 test_led.源码

复制代码

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h> 
#include <linux/delay.h>
#include <linux/gpio.h>
#ifdef CONFIG_OF
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#endif

#include <linux/fb.h>
#include <linux/device.h>
#include <linux/miscdevice.h>


#define INVALID_GPIO -1
int led1_gpio = INVALID_GPIO;
int led2_gpio = INVALID_GPIO;
int led_gpio_active = 0;

static int led_open(struct inode *inode, struct file *file)
{    
    printk("carroll led_open ok \n");

    return 0;
}

static int led_release(struct inode *inode, struct file *file)
{    
    printk("carroll led_close \n");

    return 0;
}

/* app : ioctl(fd, cmd, arg) */
static long led_ioctl(struct file *filp, unsigned int cmd,
        unsigned long arg)
{
    /* 根据传入的参数设置GPIO */
    /* cmd : 0-off, 1-on */
    /* arg : 0-1, which led */

    if ((cmd != 0) && (cmd != 1))
        return -EINVAL;
    
    if (arg > 4)
        return -EINVAL;
    
    if(arg == 0)
    {
        if(led1_gpio != INVALID_GPIO)
            gpio_set_value(led1_gpio, !cmd);
    }
    else if(arg == 1)
    {
        if(led2_gpio != INVALID_GPIO)
            gpio_set_value(led2_gpio, !cmd);
    }
    
    
    printk("carroll led_ioctl: %d \n", cmd);

    return 0;
}

static struct file_operations led_fops = {
        .owner   = THIS_MODULE,
        .open    = led_open,
        .release    = led_release,
        .unlocked_ioctl   = led_ioctl,
};

static struct miscdevice led_dev =
{
    .minor = MISC_DYNAMIC_MINOR,
    .name = "test_led",
    .fops = &led_fops,
};

static int firefly_led_probe(struct platform_device *pdev)
{
    int ret = -1;
    enum of_gpio_flags flags;
    struct device_node *hello_node = pdev->dev.of_node;

    printk("%s-%d: carroll \n",__FUNCTION__,__LINE__);

    /* register test_led dev file */
    ret = misc_register(&led_dev);
    if (ret < 0){
            printk("carroll led register err!\n");
            return ret;
    }

    /* led1 init */
    led1_gpio = of_get_named_gpio_flags(hello_node,"led1", 0,&flags);
    if (!gpio_is_valid(led1_gpio)){
        printk("carroll: invalid gpio : %d\n",led1_gpio);
        return -1;
    } 
    ret = gpio_request(led1_gpio, "test_led");
    if (ret != 0) {
        gpio_free(led1_gpio);
        printk("carroll: led1_gpio free\n");
        return -EIO;
    }
    gpio_direction_output(led1_gpio, !led_gpio_active);

    /* led2 init */
    led2_gpio = of_get_named_gpio_flags(hello_node,"led2", 0,&flags);
    if (!gpio_is_valid(led2_gpio)){
        printk("carroll: invalid gpio : %d\n",led2_gpio);
        return -1;
    } 
    ret = gpio_request(led2_gpio, "test_led");
    if (ret != 0) {
        gpio_free(led2_gpio);
        printk("carroll: led2_gpio free\n");
        return -EIO;
    }
    gpio_direction_output(led2_gpio, !led_gpio_active);


    gpio_set_value(led1_gpio, led_gpio_active);
    gpio_set_value(led2_gpio, led_gpio_active);
    mdelay(500);
    gpio_set_value(led1_gpio, !led_gpio_active);
    gpio_set_value(led2_gpio, !led_gpio_active);

    return 0;  //return Ok
}

static int firefly_led_remove(struct platform_device *pdev)
{ 
    return 0;
}

#ifdef CONFIG_OF
static const struct of_device_id of_firefly_led_match[] = {
    { .compatible = "firefly,test_led" },
    { /* Sentinel */ }
};
#endif

static struct platform_driver firefly_led_driver = {
    .probe        = firefly_led_probe,
    .remove        = firefly_led_remove,
    .driver        = {
        .name    = "test_led",
        .owner    = THIS_MODULE,
#ifdef CONFIG_OF
        .of_match_table    = of_firefly_led_match,
#endif
    },

};

static int major;
static struct class *cls;

static int __init led_init(void)
{
    printk(KERN_INFO "carroll register led dev %s\n", __FUNCTION__);

    return platform_driver_register(&firefly_led_driver);
}

static void __exit led_exit(void)
{
    platform_driver_unregister(&firefly_led_driver);
    printk(KERN_INFO "carroll unregister led dev %s\n", __FUNCTION__);
}

subsys_initcall(led_init);
module_exit(led_exit);

MODULE_AUTHOR("carroll <1247627668@qq.com>");
MODULE_DESCRIPTION("carroll led driver");
MODULE_LICENSE("GPL");

复制代码

 

  


    修改/work/rk3288/firefly-rk3288_android5.1_git_20180126/kernel/arch/arm/boot/dts/firefly-rk3288.dts
    firefly-led{
        compatible = "firefly,led";
        led-work = <&gpio8 GPIO_A2 GPIO_ACTIVE_LOW>;
        led-power = <&gpio8 GPIO_A1 GPIO_ACTIVE_LOW>;
        //carrol add start
        status = "disabled";
    };

    test-led{
        compatible = "firefly,test_led";
        led1= <&gpio8 GPIO_A1 GPIO_ACTIVE_LOW>;
        led2= <&gpio8 GPIO_A2 GPIO_ACTIVE_LOW>;
        status = "okay";
    };
        //carrol add end
    编译内核烧录即可

 内核启动过程中闪烁一次,并产生/dev/test_led文件
    添加可执行权限
    su
    chmod 777 /dev/test_led

 

    2.编写jni c程序编译为库给java调用

  hardcontrol.c源码

复制代码

#include <jni.h>  /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#include <android/log.h>  /* liblog */

//__android_log_print(ANDROID_LOG_DEBUG, "JNIDemo", "native add ...");

 
#if 0
typedef struct {
    char *name;          /* Java里调用的函数名 */
    char *signature;    /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */
    void *fnPtr;          /* C语言实现的本地函数 */
} JNINativeMethod;
#endif

static jint fd;

jint ledOpen(JNIEnv *env, jobject cls)
{
    fd = open("/dev/test_led", O_RDWR);
    __android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledOpen /dev/test_led: %d", fd);
    if (fd >= 0)
        return 0;
    else
        return -1;
}

void ledClose(JNIEnv *env, jobject cls)
{
    __android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledClose ...");
    close(fd);
}


jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status)
{
    int ret = ioctl(fd, status, which);
    __android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledCtrl : %d, %d, %d", which, status, ret);
    return ret;
}


static const JNINativeMethod methods[] = {
    {"ledOpen", "()I", (void *)ledOpen},
    {"ledClose", "()V", (void *)ledClose},
    {"ledCtrl", "(II)I", (void *)ledCtrl},
};




/* System.loadLibrary */
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
    JNIEnv *env;
    jclass cls;

    if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {
        return JNI_ERR; /* JNI version not supported */
    }
    cls = (*env)->FindClass(env, "com/thisway/hardlibrary/HardControl");
    if (cls == NULL) {
        return JNI_ERR;
    }

    /* 2. map java hello <-->c c_hello */
    if ((*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0])) < 0)
        return JNI_ERR;

    return JNI_VERSION_1_4;
}

复制代码

 

根据rk3288 android5.1 linux3.1编译库,必须使用arm-linux-gcc库(也可采用android studio cmake或ndk编译)

复制代码

  arm-linux-gcc -fPIC -shared hardcontrol.c -o libhardcontrol.so -I /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/  -nostdlib /work/rk3288/firefly-rk3288_android5.1_git_20180126/prebuilts/ndk/9/platforms/android-21/arch-arm/usr/lib/libc.so  -I /work/rk3288/firefly-rk3288_android5.1_git_20180126/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/include  /work/rk3288/firefly-rk3288_android5.1_git_20180126/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/liblog.so

复制代码

 

没有安装arm-linux-gcc的可以按照以下方法

复制代码

安装交叉编译工具

    sudo tar xvzf arm-linux-gcc-4.5.1-v6-vfp-20120301.tgz -C /

    注意: C 后面有个空格,并且 C 是大写的,它是英文单词“ Change”的第一个字母,在此 是改变目录的意思。
    执行该命令,将把 arm-linux-gcc 安装到/opt/FriendlyARM/toolschain/4.5.1 目录。

    Step2:把编译器路径加入系统环境变量,运行命令
    sudo gedit ~/.bashrc
    编辑 /root/.bashrc 文件, 注意“bashrc”前面有一个“.”,修改最后一行为
    export PATH=$PATH:/opt/FriendlyARM/toolschain/4.5.1/bin
    注意路径一定要写对,否则将不会有效。
    如图,保存退出

复制代码

 

编译产生libhardcontrol.so库文件,app将会使用到

   

3.app调用jni静态链接库操作底层驱动

android app包结构必须相同,上边jni程序已经指定class名为"com/thisway/hardlibrary/HardControl",

在app/libs/armeabi/目录下添加编译好的库,没有目录自己新建目录

MainActivity.java

复制代码

package com.thisway.app_0001_leddemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.view.View;
import android.widget.CheckBox;
import android.widget.Toast;
import com.thisway.hardlibrary.*;

public class MainActivity extends AppCompatActivity {

    private boolean ledon = false;
    private Button button = null;
    private CheckBox checkBoxLed1 = null;
    private CheckBox checkBoxLed2 = null;
    private CheckBox checkBoxLed3 = null;
    private CheckBox checkBoxLed4 = null;

    class MyButtonListener implements View.OnClickListener {
        @Override
        public void onClick(View v) {
            ledon = !ledon;
            if (ledon) {
                button.setText("ALL OFF");
                checkBoxLed1.setChecked(true);
                checkBoxLed2.setChecked(true);
                checkBoxLed3.setChecked(true);
                checkBoxLed4.setChecked(true);

                for (int i = 0; i < 4; i++)
                    HardControl.ledCtrl(i, 1);
            }
            else {
                button.setText("ALL ON");
                checkBoxLed1.setChecked(false);
                checkBoxLed2.setChecked(false);
                checkBoxLed3.setChecked(false);
                checkBoxLed4.setChecked(false);

                for (int i = 0; i < 4; i++)
                    HardControl.ledCtrl(i, 0);
            }
        }
    }

    public void onCheckboxClicked(View view) {
        // Is the view now checked?
        boolean checked = ((CheckBox) view).isChecked();

        // Check which checkbox was clicked
        switch(view.getId()) {
            case R.id.LED1:
                if (checked) {
                    // Put some meat on the sandwich
                    Toast.makeText(getApplicationContext(), "LED1 on", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(0, 1);
                }
                else {
                    // Remove the meat
                    Toast.makeText(getApplicationContext(), "LED1 off", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(0, 0);
                }
                break;
            case R.id.LED2:
                if (checked) {
                    // Put some meat on the sandwich
                    Toast.makeText(getApplicationContext(), "LED2 on", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(1, 1);
                }
                else {
                    // Remove the meat
                    Toast.makeText(getApplicationContext(), "LED2 off", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(1, 0);
                }
                break;

            case R.id.LED3:
                if (checked) {
                    // Put some meat on the sandwich
                    Toast.makeText(getApplicationContext(), "LED3 on", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(2, 1);
                }
                else {
                    // Remove the meat
                    Toast.makeText(getApplicationContext(), "LED3 off", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(2, 0);
                }
                break;

            case R.id.LED4:
                if (checked) {
                    // Put some meat on the sandwich
                    Toast.makeText(getApplicationContext(), "LED4 on", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(3, 1);
                }
                else {
                    // Remove the meat
                    Toast.makeText(getApplicationContext(), "LED4 off", Toast.LENGTH_SHORT).show();
                    HardControl.ledCtrl(3, 0);
                }
                break;
            // TODO: Veggie sandwich
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button = (Button) findViewById(R.id.BUTTON);

        HardControl.ledOpen();

        checkBoxLed1 = (CheckBox) findViewById(R.id.LED1);
        checkBoxLed2 = (CheckBox) findViewById(R.id.LED2);
        checkBoxLed3 = (CheckBox) findViewById(R.id.LED3);
        checkBoxLed4 = (CheckBox) findViewById(R.id.LED4);

        button.setOnClickListener(new MyButtonListener());
/*
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                // Perform action on click
                ledon = !ledon;
                if (ledon)
                    button.setText("ALL OFF");
                else
                    button.setText("ALL ON");
            }
        });
*/
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

复制代码

 

HardControl.java

复制代码

package com.thisway.hardlibrary;

public class HardControl {
    public static native int ledCtrl(int which, int status);
    public static native int ledOpen();
    public static native void ledClose();

    static {
        try {
            System.loadLibrary("hardcontrol");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要在Android应用程序中调用JNI操作指示灯,您需要完成以下步骤: 1.编写一个C或C++文件,其中包含您要执行的JNI操作。 2.将C或C++文件编译为共享库(.so文件)。 3.将共享库文件复制到您的Android项目的jniLibs目录中。 4.在Android项目中创建一个Java类,其中包含本地方法声明,并使用native关键字标记本地方法。 5.在Java类中加载共享库文件,并使用System.loadLibrary()方法加载库文件。 6.使用您在C或C++文件中编写的JNI代码实现本地Java方法。 7.最后,在您的Android应用程序中调用本地Java方法即可。 以下是一个简单的示例,说明如何在Android应用程序中使用JNI操作指示灯: C/C++文件: ```c #include <jni.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> JNIEXPORT void JNICALL Java_com_example_testjni_MainActivity_turnOnLed(JNIEnv *env, jobject obj) { int fd; fd = open("/sys/class/leds/led1/brightness", O_WRONLY); if (fd != -1) { write(fd, "1", 1); close(fd); } } JNIEXPORT void JNICALL Java_com_example_testjni_MainActivity_turnOffLed(JNIEnv *env, jobject obj) { int fd; fd = open("/sys/class/leds/led1/brightness", O_WRONLY); if (fd != -1) { write(fd, "0", 1); close(fd); } } ``` Java类: ```java package com.example.testjni; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { static { System.loadLibrary("led"); } public native void turnOnLed(); public native void turnOffLed(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); turnOnLed(); // 延迟2秒 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } turnOffLed(); } } ``` 在此示例中,我们使用JNI打开和关闭指示灯。在C/C++文件中,我们打开/sys/class/leds/led1/brightness文件,并将其设置为“1”或“0”,以打开或关闭LED灯。在Java类中,我们使用System.loadLibrary()方法加载共享库文件,并使用native关键字标记本地方法。然后,在onCreate()方法中,我们调用turnOnLed()方法打开LED灯,并在2秒后调用turnOffLed()方法关闭LED灯。 请注意,在使用JNI时,您需要小心处理内存分配和释放,以避免内存泄漏和其他问题。 ### 回答2: 在Android上调用JNI来操作指示灯需要经过以下几个步骤: 1. 首先,在Android上需要创建一个JNI接口来与底层硬件交互。使用JNI接口可以连接Java层和底层C/C++代码。可以在JNI接口中定义对应的函数来操作指示灯,比如打开和关闭指示灯。 2. 在Java层中,通过加载和调用JNI接口来实现对指示灯的控制。在Java代码中使用`System.loadLibrary("your_jni_library")`方法来加载JNI库。 3. 在C/C++层,实现JNI接口中定义的函数。可以使用底层硬件通信库,比如WiringPi、OpenCV等,在C/C++代码中操作底层硬件。 4. 在底层C/C++代码中,通过对指示灯所在的引脚进行驱动控制,来打开或关闭指示灯。具体的操作方式和硬件平台相关,可以通过GPIO库或相应的驱动程序来实现。 5. 在调用JNI的适当时机,可以在Android应用中的某个事件触发时调用这些JNI方法,来操作指示灯。比如在按钮点击事件发生时,调用JNI方法来打开或关闭指示灯。 需要注意的是,操作指示灯需要获取一定的硬件权限,可以通过在AndroidManifest.xml文件中声明相应的权限来获取。 通过以上步骤,我们就可以在Android上通过JNI来操作指示灯了。当调用对应的JNI方法时,就可以控制指示灯的亮灭状态。 ### 回答3: 在Android中调用JNI操作指示灯可以通过以下步骤实现: 首先,编写一个JNI的C/C++函数,用于控制指示灯的开关。可以使用特定的硬件库函数或者系统调用函数来控制指示灯的状态。这个函数需要传入一个参数,用于指定指示灯的状态,比如开启、关闭或者闪烁。 然后,在Android应用的Java代码中通过`System.loadLibrary()`方法加载之前编写好的JNI库,以便可以调用JNI函数。将该JNI函数封装到一个Java方法中,并为该方法添加`native`关键字,表示该方法是通过JNI调用的。例如: ```java public class LedController { static { System.loadLibrary("led_controller"); } public native static void controlLed(int state); // Other methods and code here... } ``` 接下来,在JNI的C/C++代码中实现`controlLed()`方法。例如,可以通过GPIO库或者Linux系统调用函数来控制指示灯的状态。根据传入的参数,调用相应的函数操作指示灯。示例代码如下: ```c #include <jni.h> // 其他可能需引用的头文件 JNIEXPORT void JNICALL Java_com_example_ledcontroller_LedController_controlLed(JNIEnv *env, jclass type, jint state) { // 执行对指示灯的控制操作 if (state == 0) { // 关闭指示灯 } else if (state == 1) { // 开启指示灯 } else if (state == 2) { // 闪烁指示灯 } } ``` 最后,在Android应用的Java代码中调用`controlLed()`方法来控制指示灯的状态。例如: ```java LedController.controlLed(1); // 开启指示灯 ``` 通过这样的步骤,就可以在Android应用中调用JNI函数来操作指示灯。当调用`controlLed()`方法时,会通过JNI加载C/C++代码并执行指定的指示灯操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值