zoukankan      html  css  js  c++  java
  • 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 
    ");
    
        return 0;
    }
    
    static int led_release(struct inode *inode, struct file *file)
    {    
        printk("carroll led_close 
    ");
    
        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 
    ", 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 
    ",__FUNCTION__,__LINE__);
    
        /* register test_led dev file */
        ret = misc_register(&led_dev);
        if (ret < 0){
                printk("carroll led register err!
    ");
                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
    ",led1_gpio);
            return -1;
        } 
        ret = gpio_request(led1_gpio, "test_led");
        if (ret != 0) {
            gpio_free(led1_gpio);
            printk("carroll: led1_gpio free
    ");
            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
    ",led2_gpio);
            return -1;
        } 
        ret = gpio_request(led2_gpio, "test_led");
        if (ret != 0) {
            gpio_free(led2_gpio);
            printk("carroll: led2_gpio free
    ");
            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
    ", __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
    ", __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();
            }
        }
    }

    然后就可通过app控制两个gpio

  • 相关阅读:
    C# partial 作用
    C#中internal关键字是什么意思?什么叫做“只能在包含它的程序集中访问该方法”
    [转]利用.NET中的反射机制实现IList到DataTable的转换
    你可能已经知道或者不知道的ASP.NET 2.0技巧
    SQL Server基本函数详细介绍--字符串函数
    在Web.config配置文件中自定义配置节点
    SQL SERVER事务处理
    专用于SqlServer2005的高效分页存储过程(支持多字段任意排序,不要求排序字段唯一)
    SQL SERVER 高效存储过程分页(Max/Min方法)
    该字符串未被识别为有效的 DateTime
  • 原文地址:https://www.cnblogs.com/CZM-/p/9622663.html
Copyright © 2011-2022 走看看